/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * (C) Copyright IBM Corporation 2006-2011. * (C) Rice University 2010-2011. * * Code contributed to the X10 project by Rice under XTENLANG-2685. */ package x10.visit; import polyglot.ast.*; import polyglot.frontend.Job; import polyglot.types.ClassType; import polyglot.types.FieldInstance; import polyglot.types.LocalDef; import x10.types.MethodInstance; import polyglot.types.Context; import polyglot.types.Name; import polyglot.types.NoClassException; import polyglot.types.QName; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.TypeSystem_c; import polyglot.types.Types; import polyglot.types.LocalInstance; import polyglot.types.VarInstance; import polyglot.types.VarDef; import polyglot.util.CollectionUtil; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.visit.ContextVisitor; import polyglot.visit.ErrorHandlingVisitor; import polyglot.visit.NodeVisitor; import x10.ast.*; import x10.types.*; import x10.constraint.*; import x10.emitter.*; import x10.X10CompilerOptions; import x10.util.Synthesizer; import x10.Configuration; import x10.extension.X10Ext; import java.util.*; /** * Implementation of the communication optimizations described in * "Communication Optimizations for Distirbuted Memory X10 Programs" by * Barik, Zhao, Grove, Peshansky, Budimlic and Sarkar published in IPDPS 2011. * * The core idea is to reduce redundant data serialization via * compiler transformations such as scalar replacement and task localization. * Optimization opportunities can be exposed via loop transformations such * as splitting, tiling, and distribution. * * @author jisheng zhao * @author raj barik */ public class CommunicationOptimizer extends ContextVisitor { private final TypeSystem_c xts; private final X10NodeFactory_c xnf; private final Synthesizer synth; private final boolean shouldOpt; public CommunicationOptimizer(Job job, TypeSystem ts, NodeFactory nf) { super(job, ts, nf); xts = (TypeSystem_c) ts; xnf = (X10NodeFactory_c) nf; synth = new Synthesizer(xnf, xts); shouldOpt = ((X10CompilerOptions)job.extensionInfo().getOptions()).x10_config.OPTIMIZE_COMMUNICATIONS; } private static Name getTmp() { return Name.makeFresh("__comopt__var__"); } public Node override(Node parent, Node n) { if (n instanceof Eval) { } return null; } protected Node leaveCall(Node parent, Node old, Node n, NodeVisitor v) throws SemanticException { if (shouldOpt) { if (n instanceof Async) return visitAsync((Async)n); else if (n instanceof AtEach) return visitAtEach((AtEach)n); else if (n instanceof AtStmt) return visitAt((AtStmt)n); else if (n instanceof Block) { Block b = (Block) n; /*if (parent instanceof X10Loop_c) return processX10Loop(parent, b); else if (parent instanceof Loop_c) return processLoop(parent, b); else*/ return processNormalBlock(parent, b); } } return n; } /** * Visit the async closure * * @param async */ protected Async visitAsync(Async a) throws SemanticException { List<VarInstance<? extends VarDef>> env = a.asyncDef().capturedEnvironment(); List<VarInstance<? extends VarDef>> env1 = new ArrayList<VarInstance<? extends VarDef>>(env); Stmt newBody = processAsync(a, (Block)a.body(), env1); Async newAsync = a.body(newBody); newAsync.asyncDef().setCapturedEnvironment(env1); return newAsync; } /** * Visit the ateach closure * * @param ateach */ protected AtEach visitAtEach(AtEach ateach) throws SemanticException { List<VarInstance<? extends VarDef>> env = ateach.atDef().capturedEnvironment(); List<VarInstance<? extends VarDef>> env1 = new ArrayList<VarInstance<? extends VarDef>>(env); Stmt newBody = processAtEach(ateach, (Block)ateach.body(), env1); System.out.println("proc ateach"); AtEach newAteach = (AtEach)ateach.body(newBody); newAteach.atDef().setCapturedEnvironment(env1); return newAteach; } /** * Visit the ateach closure * * @param ateach */ protected Stmt visitAt(AtStmt at) throws SemanticException { List<VarInstance<? extends VarDef>> env = at.atDef().capturedEnvironment(); List<VarInstance<? extends VarDef>> env1 = new ArrayList<VarInstance<? extends VarDef>>(env); Stmt newBody = processAt(at, (Block)at.body(), env1); AtStmt newAt = at.body(newBody); newAt.atDef().setCapturedEnvironment(env1); return newAt; } /** * Process the block in loop closure * * @param parent loop node * @param block */ private Block processLoop(Node parent, Block b) { // Let's handle the X10Loop's block List<Stmt> ss = new ArrayList<Stmt>(); for (Stmt s : b.statements()) { if (s instanceof Async || s instanceof AtEach || s instanceof AtStmt || s instanceof X10Loop/* || s instanceof Future */|| s instanceof Loop_c) { ArrayList<Stmt> stmtList = scalarReplaceMap.get(s.position()); if (stmtList != null && stmtList.size() != 0) { // Process the statements for (Stmt ts : stmtList) { Stmt stmt = processStmt(ts, (Loop_c)parent, null); if (stmt != null) { ss.add(stmt); } } } ss.add(s); continue; } Stmt stmt = processStmt(s, (Loop_c)parent, null); if (stmt != null) ss.add(stmt); } return b.statements(ss); } /** * Process the block in X10Loop closure * TODO: if this process is necessary? or just use normal loop handler to replace * @param parent X10 loop node * @param block */ private Block processX10Loop(Node parent, Block b) { // Let's handle the X10Loop's block List<Stmt> ss = new ArrayList<Stmt>(); for (Stmt s : b.statements()) { if (s instanceof Async || s instanceof AtEach || s instanceof AtStmt || s instanceof X10Loop/* || s instanceof Future*/) { ArrayList<Stmt> stmtList = scalarReplaceMap.get(((X10Loop)s).position()); if (stmtList != null && stmtList.size() != 0) { // Process the statements for (Stmt ts : stmtList) { Stmt stmt = processStmt(ts, (X10Loop)parent, null); if (stmt != null) { ss.add(stmt); } } } ss.add(s); continue; } Stmt stmt = processStmt(s, (X10Loop)parent, null); if (stmt != null) ss.add(stmt); } return b.statements(ss); } /** * Process the block in async closure * * @param parent async node * @param block */ private Block processAsync(Node parent, Block b, List<VarInstance<? extends VarDef>> env) throws SemanticException { // Let's handle the async's block List<Stmt> ss = new ArrayList<Stmt>(); // Add the scalar replaced stmts for (Stmt s : b.statements()) { if (s instanceof Async || s instanceof AtEach || s instanceof AtStmt || s instanceof X10Loop || s instanceof Loop_c) { ArrayList<Stmt> stmtList = scalarReplaceMap.get(s.position()); if (stmtList != null && stmtList.size() != 0) { // Process the statements for (Stmt ts : stmtList) { Stmt stmt = processStmt(ts, (Async_c)parent, env); if (stmt != null) { ss.add(stmt); } else ss.add(ts); } } if (s instanceof AtStmt) ss.add(localizeAt((AtStmt)s)); else ss.add(s); continue; } // TODO: check place id Stmt stmt = processStmt(s, (Async_c)parent, env); if (stmt != null) { ss.add(stmt); } } return b.statements(ss); } /** * Process the block in ateach closure * * @param parent ateach node * @param block */ private Block processAtEach(Node parent, Block b, List<VarInstance<? extends VarDef>> env) throws SemanticException { // Let's handle the ateach's block List<Stmt> ss = new ArrayList<Stmt>(); // Add the scalar replaced stmts for (Stmt s : b.statements()) { if (s instanceof Async || s instanceof AtEach || s instanceof AtStmt || s instanceof X10Loop || s instanceof Loop_c) { ArrayList<Stmt> stmtList = scalarReplaceMap.get(s.position()); if (stmtList != null && stmtList.size() != 0) { // Process the statements for (Stmt ts : stmtList) { Stmt stmt = processStmt(ts, (AtEach)parent, env); if (stmt != null) { ss.add(stmt); } else ss.add(ts); } } if (s instanceof AtStmt) ss.add(localizeAt((AtStmt)s)); else ss.add(s); continue; } // TODO: AtEach special processing, i.e. checking place id Stmt stmt = processStmt(s, (AtEach)parent, env); if (stmt != null) ss.add(stmt); } return b.statements(ss); } /** * Process the block in at stmt * * @param parent at node * @param block * @param closure env */ private Block processAt(Node parent, Block b, List<VarInstance<? extends VarDef>> env) throws SemanticException { // Let's handle the at's block List<Stmt> ss = new ArrayList<Stmt>(); // Add the scalar replaced stmts for (Stmt s : b.statements()) { if (s instanceof Async || s instanceof AtEach || s instanceof AtStmt || s instanceof X10Loop || s instanceof Loop_c) { ArrayList<Stmt> stmtList = scalarReplaceMap.get(s.position()); // Process the statements if (stmtList != null && stmtList.size() > 0) for (Stmt ts : stmtList) { Stmt stmt = processStmt(ts, (AtStmt)parent, env); if (stmt != null) { ss.add(stmt); } else ss.add(ts); } if (s instanceof AtStmt) ss.add(localizeAt((AtStmt)s)); else ss.add(s); continue; } // TODO: At special processing, i.e. checking place id Stmt stmt = processStmt(s, (AtStmt)parent, env); if (stmt != null) ss.add(stmt); } return b.statements(ss); } /** * Process the normal block which is not async, ateach or at * * @param block */ private Block processNormalBlock(Node parent, Block b) throws SemanticException { // For those block those parent are the scalar replacement related constructs, we skip if (parent instanceof Async || parent instanceof AtEach || parent instanceof AtStmt) return b; // Let's hande the normal block List<Stmt> ss = new ArrayList<Stmt>(); for (Stmt s : b.statements()) { if (s instanceof Async || s instanceof AtEach || s instanceof AtStmt || s instanceof Loop_c) { ArrayList<Stmt> stmtList = scalarReplaceMap.get(s.position()); if (stmtList != null) { // Insert the scalar replacement statements here ss.addAll(stmtList); } } if (s instanceof AtStmt) ss.add(localizeAt((AtStmt)s)); else ss.add(s); } return b.statements(ss); } /** * Process the stmt inside the async, ateach and at * * @param stmt * @param closure */ private Stmt processStmt(Stmt s, Term outerClosure, List<VarInstance<? extends VarDef>> env) { if (s instanceof Eval_c) { if (((Eval)s).expr() instanceof X10Call_c) return xnf.Eval(s.position(), handleCall((X10Call_c)((Eval)s).expr(), outerClosure, env)); else if (((Eval)s).expr() instanceof Assign_c) return xnf.Eval(s.position(), handleAssign((Assign)((Eval)s).expr(), outerClosure, env)); return s; } else if (s instanceof X10LocalDecl_c) return handleLocalDecl((X10LocalDecl_c)s, outerClosure, env); else if (s instanceof X10Return_c) return handleX10Return((X10Return_c)s, outerClosure, env); else if (s instanceof If) return handleIf((If)s, outerClosure, env); else return s; } /** * Handle the assign expr * * @param Assign expr * @param the outer closure * @param closure env */ private Expr handleAssign(Assign assign, Term outerClosure, List<VarInstance<? extends VarDef>> env) { // Only the settable assign need to be considered for handling the left side array ref and // index expr; if (assign instanceof SettableAssign) { assign = handleSettableAssign((SettableAssign)assign, outerClosure, env); } // Check the right side of expr Expr right = assign.right(); if (right instanceof X10Call_c) { assign = assign.right(handleCall((X10Call_c)right, outerClosure, env)); } else if (right instanceof Binary) { assign = assign.right(handleBinary((Binary)right, outerClosure, env)); } else if (right instanceof X10Field_c) { assign = assign.right(handleField((X10Field_c)right, outerClosure, env)); } return assign; } /** * Handle the case for Settable Assign * * @param Settable Assign expr * @param the outer closure */ private SettableAssign handleSettableAssign(SettableAssign setAssign, Term outerClosure, List<VarInstance<? extends VarDef>> env) { Expr array = setAssign.array(); if (array instanceof X10Call_c) setAssign = setAssign.array(handleCall((X10Call_c)array, outerClosure, env)); ArrayList<Expr> newIndex = new ArrayList<Expr>(); Iterator<Expr> indexIter = setAssign.index().iterator(); while (indexIter.hasNext()) { Expr index = indexIter.next(); if (index instanceof X10Call_c) newIndex.add(handleCall((X10Call_c)index, outerClosure, env)); else if (index instanceof Binary) newIndex.add(handleBinary((Binary)index, outerClosure, env)); else newIndex.add(index); } setAssign = setAssign.index(newIndex); return setAssign; } /** * Handle the case for method call * * @param method call expr * @param the outer closure * @param closure environment */ private Expr handleCall(X10Call_c call, Term outerClosure, List<VarInstance<? extends VarDef>> env) { // Handling the nested call AST if (call.target() instanceof X10Call_c) { call = (X10Call_c)call.target(handleCall((X10Call_c)call.target(), outerClosure, env)); } if (hasInvariantReceiver(call.target(), outerClosure, env)) { Type classType = call.target().type(); // Verify the array if (xts.isArray(classType) && !xts.isX10DistArray(classType) && call.methodInstance().name().equals(OperatorNames.APPLY)) { // Check the method arguments, here we only handle .apply(ind) List<Expr> arguments = call.arguments(); for (Expr arg : arguments) { if (!checkInvariant(arg, outerClosure, env)) // There's variant, so can't apply scalar replacement return call; } // Create the new local variable which is final Position pos = call.position(); Name srName = Name.makeFresh(getReceiverName(call.target())); Type valType = TypeSystem_c.getArrayComponentType(classType); LocalDef srDef = xts.localDef(pos, xts.Final(), Types.ref(valType), srName); // Create the scalar replacement statement LocalDecl srLocalDecl = xnf.LocalDecl(pos, xnf.FlagsNode(pos, xts.Final()), xnf.CanonicalTypeNode(pos, Types.ref(valType)), xnf.Id(pos, srName), call).localDef(srDef); regScalarReplace(outerClosure, srLocalDecl); // Create the scalar assignment statement X10Local_c valLocal = (X10Local_c)xnf.Local(pos, xnf.Id(pos, srName)).localInstance(srDef.asInstance()).type(valType); if (env != null) env.add(valLocal.localInstance()); return valLocal; } } return call; } /** * Handle the case for class field * * @param class field ref * @param the outer closure * @param closure environment */ private Expr handleField(X10Field_c field, Term outerClosure, List<VarInstance<? extends VarDef>> env) { if (!hasInvariantReceiver(field.target(), outerClosure, env)) return field; Position pos = field.position(); Name srName = Name.makeFresh(field.name().toString()); Type valType = field.fieldInstance().type(); LocalDef srDef = xts.localDef(pos, xts.Final(), Types.ref(valType), srName); // Create the scalar replacement statement Id srId = xnf.Id(pos, srName); LocalDecl srLocalDecl = xnf.LocalDecl(pos, xnf.FlagsNode(pos, xts.Final()), xnf.CanonicalTypeNode(pos, Types.ref(valType)), srId, field).localDef(srDef); regScalarReplace(outerClosure, srLocalDecl); // Create the scalar assignment statement X10Local_c valLocal = (X10Local_c)xnf.Local(pos, srId).localInstance(srDef.asInstance()).type(srLocalDecl.type().typeRef().get()); if (env != null) env.add(valLocal.localInstance()); return valLocal; } /** * Handle the case for local declaration * * @param the local declaration statement * @param the outer closure */ private Stmt handleLocalDecl(X10LocalDecl_c localDecl, Term outerClosure, List<VarInstance<? extends VarDef>> env) { if (localDecl.init() instanceof X10Call_c) { X10Call_c call = (X10Call_c)localDecl.init(); if (hasInvariantReceiver(call.target(), outerClosure, env)) { Type classType = call.target().type(); // Verify the array if (xts.isArray(classType) && !xts.isX10DistArray(classType) && call.methodInstance().name().equals(OperatorNames.APPLY)) { // Check the method arguments, here we only handle .apply(ind) List<Expr> arguments = call.arguments(); for (Expr arg : arguments) { if (!checkInvariant(arg, outerClosure, env)) // There's variant, so can't apply scalar replacement return (Stmt)localDecl; } // Create the new local variable which is final Position pos = localDecl.position(); Name srName = Name.makeFresh(localDecl.name().toString()); LocalDef srDef = xts.localDef(pos, xts.Final(), localDecl.type().typeRef(), srName); // Create the scalar replacement statement Id srId = xnf.Id(pos, srName); LocalDecl srLocalDecl = xnf.LocalDecl(pos, xnf.FlagsNode(pos, xts.Final()), xnf.CanonicalTypeNode(pos, localDecl.type().typeRef()), srId, call).localDef(srDef); regScalarReplace(outerClosure, srLocalDecl); // Create the scalar assignment statement // Name tmpName = Name.make(localDecl.name().toString()); // LocalDef lDef = xts.localDef(pos, xts.NoFlags(), localDecl.type().typeRef(), tmpName); X10Local_c valLocal = (X10Local_c)xnf.Local(pos, srId).localInstance(srDef.asInstance()).type(srLocalDecl.type().typeRef().get()); if (env != null) env.add(valLocal.localInstance()); LocalDecl newLocalDecl = localDecl.init(valLocal); // xnf.LocalDecl(pos, xnf.FlagsNode(pos, xts.Final()), xnf.CanonicalTypeNode(pos, localDecl.type().typeRef()), xnf.Id(pos, tmpName), valLocal).localDef(lDef); return newLocalDecl; } } } else if (localDecl.init() instanceof X10Field_c) { X10Field_c field = (X10Field_c)localDecl.init(); if (!hasInvariantReceiver(field.target(), outerClosure, env)) return (Stmt)localDecl; Position pos = localDecl.position(); Name srName = Name.makeFresh(localDecl.name().toString()); LocalDef srDef = xts.localDef(pos, xts.Final(), localDecl.type().typeRef(), srName); // Create the scalar replacement statement Id srId = xnf.Id(pos, srName); LocalDecl srLocalDecl = xnf.LocalDecl(pos, xnf.FlagsNode(pos, xts.Final()), xnf.CanonicalTypeNode(pos, localDecl.type().typeRef()), srId, field).localDef(srDef); regScalarReplace(outerClosure, srLocalDecl); // Create the scalar assignment statement X10Local_c valLocal = (X10Local_c)xnf.Local(pos, srId).localInstance(srDef.asInstance()).type(srLocalDecl.type().typeRef().get()); if (env != null) env.add(valLocal.localInstance()); LocalDecl newLocalDecl = localDecl.init(valLocal); return newLocalDecl; } return (Stmt)localDecl; } /** * Handle the case for local assignment * * @param local assignment expr * @param the outer closure */ private Expr handleLocalAssign(X10LocalAssign_c localAssign, Term outerClosure, List<VarInstance<? extends VarDef>> env) { if (localAssign.right() instanceof X10Call_c) { X10Call_c call = (X10Call_c)localAssign.right(); if (call.target() instanceof X10Local_c) { X10Local_c target = (X10Local_c)call.target(); // if (target.localInstance().type() instanceof X10ParsedClassType_c) { // X10ParsedClassType_c classType = (X10ParsedClassType_c)target.localInstance().type(); Type classType = target.localInstance().type(); if (xts.isArray(classType) && !xts.isX10DistArray(classType) && call.methodInstance().name().equals(OperatorNames.APPLY)) { // Handle the Array element reading, which is an array inside the async closure // Check the method arguments, here we only handle .apply(ind) List<Expr> arguments = call.arguments(); if (arguments.size() == 1) { if (checkInvariant(arguments.get(0), outerClosure, env)) { // Create the new local variable which is final Position pos = localAssign.position(); Name srName = Name.makeFresh(localAssign.local().name().toString()); Type leftType = localAssign.leftType(); LocalDef srDef = xts.localDef(pos, xts.Final(), Types.ref(leftType), srName); // Create the scalar replacement statement LocalDecl srLocalDecl = xnf.LocalDecl(pos, xnf.FlagsNode(pos, xts.Final()), xnf.CanonicalTypeNode(pos, Types.ref(leftType)), xnf.Id(pos, srName), call).localDef(srDef); regScalarReplace(outerClosure, srLocalDecl); // Create the scalar assignment statement Expr valLocal = xnf.Local(pos, xnf.Id(pos, srName)).localInstance(srDef.asInstance()).type(leftType); return localAssign.right(valLocal); } } } // } } } return localAssign; } /** * Handle the case for class field assignment * * @param class field assignment expr * @param the outer closure */ private Expr handleFieldAssign(X10FieldAssign_c fieldAssign, Term outerClosure) { if (fieldAssign.right() instanceof X10Call_c) { X10Call_c call = (X10Call_c)fieldAssign.right(); if (call.target() instanceof X10Local_c) { X10Local_c target = (X10Local_c)call.target(); // if (target.localInstance().type() instanceof X10ParsedClassType_c) { // X10ParsedClassType_c classType = (X10ParsedClassType_c)target.localInstance().type(); Type classType = target.localInstance().type(); if (xts.isArray(classType) && !xts.isX10DistArray(classType) && call.methodInstance().name().equals(OperatorNames.APPLY)) { // Handle the Array element reading, which is an array inside the async closure // Check the method arguments, here we only handle .apply(ind) List<Expr> arguments = call.arguments(); if (arguments.size() == 1) { if (checkInvariant(arguments.get(0), outerClosure, null)) { // Create the new local variable which is final Position pos = fieldAssign.position(); Name srName = Name.makeFresh(fieldAssign.name().toString()); Type leftType = fieldAssign.leftType(); LocalDef srDef = xts.localDef(pos, xts.Final(), Types.ref(leftType), srName); // Create the scalar replacement statement LocalDecl srLocalDecl = xnf.LocalDecl(pos, xnf.FlagsNode(pos, xts.Final()), xnf.CanonicalTypeNode(pos, Types.ref(leftType)), xnf.Id(pos, srName), call).localDef(srDef); regScalarReplace(outerClosure, srLocalDecl); // Create the scalar assignment statement Expr valLocal = xnf.Local(pos, xnf.Id(pos, srName)).localInstance(srDef.asInstance()).type(leftType); return fieldAssign.right(valLocal); } } } // } } } return fieldAssign; } /** * Handle the case for X10 return stmt * * @param X10 return expr * @param the outer closure */ private Stmt handleX10Return(X10Return_c retStmt, Term outerClosure, List<VarInstance<? extends VarDef>> env) { if (retStmt.expr() instanceof X10Call_c) return xnf.X10Return(retStmt.position(), handleCall((X10Call_c)retStmt.expr(), outerClosure, env), true); return retStmt; } /** * Handle the case for X10 If stmt * * @param X10 If stmt * @param the outer closure */ private Stmt handleIf(If ifStmt, Term outerClosure, List<VarInstance<? extends VarDef>> env) { if (ifStmt.cond() instanceof Binary) return ifStmt.cond(handleBinary((Binary)ifStmt.cond(), outerClosure, env)); return ifStmt; } /** * Handle the Binary expression * * @param Binary expr * @param the outer closure */ private Expr handleBinary(Binary cond, Term outerClosure, List<VarInstance<? extends VarDef>> env) { // Check left side Expr left = cond.left(); if (left instanceof Binary) cond = cond.left(handleBinary((Binary)left, outerClosure, env)); else if (left instanceof X10Call_c) cond = cond.left(handleCall((X10Call_c)left, outerClosure, env)); // Check right side Expr right = cond.right(); if (right instanceof Binary) cond = cond.right(handleBinary((Binary)right, outerClosure, env)); else if(right instanceof X10Call_c) cond = cond.right(handleCall((X10Call_c)right, outerClosure, env)); else if (right instanceof X10Field_c) { cond = cond.right(handleField((X10Field_c)right, outerClosure, env)); } return cond; } private HashMap<java.lang.Object, ArrayList<Stmt>> scalarReplaceMap = new HashMap<java.lang.Object, ArrayList<Stmt>>(); /** * Check if the input local variable is an invariant inside current block region * * @param local variable * @param the outer closure, i.e. async, ateach, at */ private boolean checkInvariant(Expr indexExpr, Term outerClosure, List<VarInstance<? extends VarDef>> env) { if (indexExpr instanceof X10Local_c) { // Local index X10Local_c indexLocal = (X10Local_c)indexExpr; // Check if the index local is invariant, i.e. the local is defined outside current closure Context context = context().pushCode(context().currentCode()); boolean isFinal = false; try { LocalInstance li = context.findLocal(indexLocal.name().id()); // if the local is defined in an outer class, then it must be final, i.e. invariant if (!context.isLocal(li.name())) isFinal = true; } catch (Exception e) {} return isFinal; } else if (indexExpr instanceof IntLit_c) // This is the case for integer constant return true; else if (indexExpr instanceof Here_c) // This is the case for here operation return true; else if (indexExpr instanceof X10Binary_c) // This is the binary index return checkInvariant(((X10Binary_c)indexExpr).left(), outerClosure, env) && checkInvariant(((X10Binary_c)indexExpr).right(), outerClosure, env); return false; } /** * Register the statement as the scalar replace statements for current async/ateach/at region * * @param current async/ateach/at region * @param s scalar replace statement */ private void regScalarReplace(Term outerClosure, Stmt s) { System.out.println("reg scalar rep " + s); ArrayList<Stmt> stmtList = scalarReplaceMap.get(outerClosure.position()); if (stmtList == null) { stmtList = new ArrayList<Stmt>(); scalarReplaceMap.put(outerClosure.position(), stmtList); } stmtList.add(s); } /** * Get the X10Field target, this is for handling the recursive case, e.g. p.q.x * * @param Receiver target */ private String getReceiverName(Receiver receiver) { if (receiver instanceof Special) return null; else if (receiver instanceof X10Local_c) return ((X10Local_c)receiver).name().toString(); else if (receiver instanceof X10Field_c) return ((X10Field_c)receiver).name().toString(); else if (receiver instanceof X10Call_c) return getReceiverName(((X10Call_c)receiver).target()); return null; } /** * Check if the given receiver is an invariant for the given ouuterClosure * * @param Receiver receiver * @param Term outerClosure */ private boolean hasInvariantReceiver(Receiver receiver, Term outerClosure, List<VarInstance<? extends VarDef>> env) { if (receiver instanceof Special) // This is for the class field whose receiver is this return true; else if (receiver instanceof X10Local_c) // The receiver is Local, check it directly return checkInvariant((X10Local_c)receiver, outerClosure, env); else if (receiver instanceof X10Field_c) // The receiver is class field, check it recursively return hasInvariantReceiver(((X10Field_c)receiver).target(), outerClosure, env); else if (receiver instanceof X10Call_c) { // Check if this is for array case X10Call_c call = (X10Call_c)receiver; if (hasInvariantReceiver(call.target(), outerClosure, env)) { // X10Local_c target = (X10Local_c)call.target(); // Type classType = target.localInstance().type(); Type classType = call.target().type(); if (xts.isArray(classType) && !xts.isX10DistArray(classType) && call.methodInstance().name().equals(OperatorNames.APPLY)) { // Check the method arguments List<Expr> arguments = call.arguments(); for (Expr arg : arguments) { if (!checkInvariant(arg, outerClosure, env)) return false; } // If receiver and all arguments are invariant, then return true return true; } else // We don't handle the normal method call and presume there's side-effect return false; } else return false; } return false; } /** * Perform localization on at stmt * e.g. at(p) {...} ==> if (p == here) {...} else at(p) {...} * * @param AtStmt at */ private Stmt localizeAt(AtStmt at) throws SemanticException { return at; // Check if AtStmt is legal for localization, i.e. the env variables should be final /*List<VarInstance<? extends VarDef>> env = at.atDef().capturedEnvironment(); for (VarInstance vi : env) { if (!vi.flags().isFinal()) return at; } Position pos = at.position(); Expr h = synth.makeStaticCall(pos, xts.Runtime(), Name.make("home"), xts.Place(), xContext()); Expr cond = xnf.Binary(pos, at.place(), Binary_c.EQ, h).type(xts.Boolean()); Stmt localizedAt = at.body(); Stmt ifStmt = xnf.If(pos, cond, localizedAt, at); return ifStmt;*/ } }