/*
* 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-2010.
*/
package x10.visit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import polyglot.ast.Assign;
import polyglot.ast.Block;
import polyglot.ast.Call;
import polyglot.ast.CanonicalTypeNode;
import polyglot.ast.Catch;
import polyglot.ast.Eval;
import polyglot.ast.Expr;
import polyglot.ast.Field;
import polyglot.ast.FieldAssign;
import polyglot.ast.FloatLit;
import polyglot.ast.For;
import polyglot.ast.Formal;
import polyglot.ast.Id;
import polyglot.ast.IntLit;
import polyglot.ast.IntLit_c;
import polyglot.ast.Local;
import polyglot.ast.LocalAssign;
import polyglot.ast.LocalDecl;
import polyglot.ast.Node;
import polyglot.ast.NodeFactory;
import polyglot.ast.Return;
import polyglot.ast.Stmt;
import polyglot.ast.Throw;
import polyglot.ast.Try;
import polyglot.ast.TypeNode;
import polyglot.ast.Unary;
import polyglot.frontend.Job;
import polyglot.main.Reporter;
import polyglot.types.ClassType;
import polyglot.types.CodeInstance;
import polyglot.types.Context;
import polyglot.types.Def;
import polyglot.types.FieldInstance;
import polyglot.types.Flags;
import polyglot.types.LocalDef;
import polyglot.types.Name;
import polyglot.types.QName;
import polyglot.types.Ref;
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.CollectionUtil; import x10.util.CollectionFactory;
import polyglot.util.InternalCompilerError;
import polyglot.util.Position;
import polyglot.visit.ContextVisitor;
import polyglot.visit.NodeVisitor;
import x10.Configuration;
import x10.ast.AnnotationNode;
import x10.ast.Async;
import x10.ast.AtEach;
import x10.ast.AtExpr;
import x10.ast.AtStmt;
import x10.ast.Atomic;
import x10.ast.Closure;
import x10.ast.DepParameterExpr;
import x10.ast.Finish;
import x10.ast.FinishExpr;
import x10.ast.Here;
import x10.ast.Here_c;
import x10.ast.Next;
import x10.ast.Offer;
import x10.ast.Resume;
import x10.ast.SettableAssign;
import x10.ast.Tuple;
import x10.ast.When;
import x10.ast.X10Binary_c;
import x10.ast.X10Call;
import x10.ast.X10CanonicalTypeNode;
import x10.ast.X10Cast;
import x10.ast.X10Formal;
import x10.ast.X10Instanceof;
import x10.ast.X10New;
import x10.ast.X10Special;
import x10.ast.X10Unary_c;
import x10.constraint.XFailure;
import x10.constraint.XVar;
import x10.extension.X10Ext;
import x10.extension.X10Ext_c;
import x10.optimizations.ForLoopOptimizer;
import x10.types.AsyncInstance;
import x10.types.AtDef;
import x10.types.AtInstance;
import x10.types.ClosureDef;
import x10.types.ConstrainedType;
import x10.types.X10ClassDef;
import x10.types.X10ClassType;
import x10.types.X10ConstructorInstance;
import x10.types.MethodInstance;
import x10.types.X10Def;
import x10.types.X10FieldInstance;
import x10.types.X10ParsedClassType;
import x10.types.checker.Converter;
import x10.types.checker.PlaceChecker;
import x10.types.constants.StringValue;
import x10.types.constraints.CConstraint;
import x10.types.constraints.XConstrainedTerm;
import x10.util.AltSynthesizer;
import x10.util.AnnotationUtils;
import x10.util.ClosureSynthesizer;
import x10.util.Synthesizer;
import x10.util.synthesizer.InstanceCallSynth;
import x10.visit.Desugarer.Substitution;
import x10cuda.ast.CUDAKernel;
/**
* Visitor to desugar the AST before code generation.
*
* NOTE: all the nodes created in the Desugarer must have the appropriate type information.
* The NodeFactory methods do not fill in the type information. Use the helper methods available
* in the Desugarer to create expressions, or see how the type information is filled in for other
* types of nodes elsewhere in the Desugarer. TODO: factor out the helper methods into the
* {@link Synthesizer}.
*/
public class Lowerer extends ContextVisitor {
private final Synthesizer synth;
private final AltSynthesizer altsynth;
public Lowerer(Job job, TypeSystem ts, NodeFactory nf) {
super(job, ts, nf);
synth = new Synthesizer(nf, ts);
altsynth = new AltSynthesizer(ts, nf);
}
private int count;
//Collecting Finish Use: store reducer
private Stack<FinishExpr> reducerS = new Stack<FinishExpr>();
private Stack<Local> clockStack = new Stack<Local>();
private int flag = 0;
private Name getTmp() {
return Name.make("__lowerer__var__" + (count++) + "__");
}
private static final Name RUN_AT = Name.make("runAt");
private static final Name EVAL_AT = Name.make("evalAt");
private static final Name RUN_ASYNC = Name.make("runAsync");
private static final Name RUN_UNCOUNTED_ASYNC = Name.make("runUncountedAsync");
private static final Name HOME = Name.make("home");
private static final Name HERE_INT = Name.make("hereInt");
private static final Name NEXT = Name.make("advanceAll");
private static final Name RESUME = Name.make("resumeAll");
private static final Name DROP = Name.make("drop");
private static final Name MAKE = Name.make("make");
private static final Name AWAIT_ATOMIC = Name.make("awaitAtomic");
private static final Name ENTER_ATOMIC = Name.make("enterAtomic");
private static final Name ENSURE_NOT_IN_ATOMIC = Name.make("ensureNotInAtomic");
private static final Name EXIT_ATOMIC = Name.make("exitAtomic");
private static final Name START_FINISH = Name.make("startFinish");
private static final Name PUSH_EXCEPTION = Name.make("pushException");
private static final Name STOP_FINISH = Name.make("stopFinish");
private static final Name PLACES = Name.make("places");
private static final Name RESTRICTION = Name.make("restriction");
private static final Name CONVERT = Converter.operator_as;
private static final Name CONVERT_IMPLICITLY = Converter.implicit_operator_as;
private static final Name DIST = Name.make("dist");
private static final Name XOR = Name.make("xor");
private static final Name FENCE = Name.make("fence");
private static final QName IMMEDIATE = QName.make("x10.compiler.Immediate");
private static final QName PRAGMA = QName.make("x10.compiler.Pragma");
private static final QName REF = QName.make("x10.compiler.Ref");
private static final QName UNCOUNTED = QName.make("x10.compiler.Uncounted");
private static final QName REMOTE_OPERATION = QName.make("x10.compiler.RemoteOperation");
private static final QName ASYNC_CLOSURE = QName.make("x10.compiler.AsyncClosure");
private static final Name START_COLLECTING_FINISH = Name.make("startCollectingFinish");
private static final Name STOP_COLLECTING_FINISH = Name.make("stopCollectingFinish");
private static final Name OFFER = Name.make("makeOffer");
//added for scalable finish
private static final Name START_LOCAL_FINISH = Name.make("startLocalFinish");
private static final Name START_SIMPLE_FINISH = Name.make("startSimpleFinish");
public Node override(Node parent, Node n) {
if (n instanceof Finish) {
Finish finish = (Finish) n;
if (! finish.clocked())
// Follow normal procedure
return null;
// Translate clocked finish S ==>
// var clock_??1:Clock=null;
// finish
// try {
// val clock_??2 = Clock.make();
// clock_??1=clock_??2;
// S; //--> nested clocked async T ==> async clocked(clock_??2) T
// } finally {
// clock_???.drop();
// }
// TODO: Simplify this to finish { val clock?? = Clock.make(); try { S} finally{ clock??.drop();}}
Context xc = context();
Position pos = finish.position();
Name name = xc.makeFreshName("clock");
Flags flags = Flags.FINAL;
Type type = ts.Clock();
final Name varName = xc.getNewVarName();
final LocalDef li = ts.localDef(pos, flags, Types.ref(type), varName);
final Id varId = nf.Id(pos, varName);
final Local ldRef = (Local) nf.Local(pos, varId).localInstance(li.asInstance()).type(type);
clockStack.push(ldRef);
final Name outerVarName = xc.getNewVarName();
final LocalDef outerLi = ts.localDef(pos, flags, Types.ref(type), outerVarName);
final Id outerVarId = nf.Id(pos, outerVarName);
final Local outerLdRef = (Local) nf.Local(pos, outerVarId).localInstance(outerLi.asInstance()).type(type);
try {
Expr clock = synth.makeStaticCall(pos, type, MAKE, type, xc);
final TypeNode tn = nf.CanonicalTypeNode(pos, type);
Expr nullLit = nf.NullLit(pos).type(type);
final LocalDecl outerLd = nf.LocalDecl(pos, nf.FlagsNode(pos, Flags.NONE), tn, outerVarId, nullLit).localDef(outerLi);
Block block = synth.toBlock(finish.body());
final LocalDecl ld = nf.LocalDecl(pos, nf.FlagsNode(pos, flags), tn, varId, clock).localDef(li);
Stmt assign = nf.Eval(pos, synth.makeAssign(pos, outerLdRef, Assign.ASSIGN, ldRef, xc));
block = block.prepend(assign);
block = block.prepend(ld);
Eval drop = nf.Eval(pos, new InstanceCallSynth(nf, xc, pos, outerLdRef, DROP).genExpr());
Expr cond = nf.Binary(pos, outerLdRef, X10Binary_c.NE, nf.NullLit(pos).type(ts.Null())).type(ts.Boolean());
Stmt stm1 = nf.Try(pos, block, Collections.<Catch>emptyList(), nf.Block(pos, nf.If(pos, cond, drop)));
Node result = visitEdgeNoOverride(parent, nf.Block(pos, outerLd, nf.Finish(pos, stm1, false)));
return result;
} catch (SemanticException z) {
return null;
} finally {
clockStack.pop();
}
}
// handle at(p) async S and treat it as the old async(p) S.
if (n instanceof AtStmt) {
AtStmt atStm = (AtStmt) n;
Stmt body = atStm.body();
Async async = toAsync(body);
if (async==null)
return null;
Expr place = atStm.place();
if (ts.hasSameClassDef(Types.baseType(place.type()), ts.GlobalRef())) {
try {
place = synth.makeFieldAccess(async.position(),place, ts.homeName(), context());
} catch (SemanticException e) {
}
}
List<Expr> clocks = async.clocks();
place = (Expr) visitEdgeNoOverride(atStm, place);
body = (Stmt) visitEdgeNoOverride(async, async.body());
if (clocks != null && ! clocks.isEmpty()) {
List<Expr> nclocks = new ArrayList<Expr>();
for (Expr c : clocks) {
nclocks.add((Expr) visitEdgeNoOverride(async, c));
}
clocks =nclocks;
}
try {
Expr prof = getProfile(atStm.atDef());
return visitAsyncPlace(async, place, body, atStm.atDef().capturedEnvironment(), prof);
} catch (SemanticException z) {
return null;
}
}
// handle async at(p) S and treat it as the old async(p) S.
if (n instanceof Async) {
Async async = (Async) n;
Stmt body = async.body();
AtStmt atStm = toAtStmt(body);
if (atStm==null)
return null;
Expr place = atStm.place();
if (ts.hasSameClassDef(Types.baseType(place.type()), ts.GlobalRef())) {
try {
place = synth.makeFieldAccess(async.position(),place, ts.homeName(), context());
} catch (SemanticException e) {
}
}
if (!ExpressionFlattener.isPrimary(place)) return null;
List<Expr> clocks = async.clocks();
place = (Expr) visitEdgeNoOverride(atStm, place);
body = (Stmt) visitEdgeNoOverride(atStm, atStm.body());
if (clocks != null && ! clocks.isEmpty()) {
List<Expr> nclocks = new ArrayList<Expr>();
for (Expr c : clocks) {
nclocks.add((Expr) visitEdgeNoOverride(async, c));
}
clocks =nclocks;
}
try {
Expr prof = getProfile(async.asyncDef());
return visitAsyncPlace(async, place, body, atStm.atDef().capturedEnvironment(), prof);
} catch (SemanticException z) {
return null;
}
}
if (n instanceof Eval) {
try {
Stmt s = visitEval((Eval) n);
flag = 1;
return visitEdgeNoOverride(parent, s);
}
catch (SemanticException e) {
return null;
}
}
return null;
}
//Collecting Finish Use : store reducer when enter finishR
@Override
protected NodeVisitor enterCall(Node parent, Node n) {
if (n instanceof LocalDecl){
LocalDecl f = (LocalDecl) n;
if (f.init() instanceof FinishExpr) {
reducerS.push((FinishExpr) f.init());
}
}
if (n instanceof Eval) {
if (((Eval) n).expr() instanceof Assign) {
Assign f = (Assign) ((Eval)n).expr();
Expr right = f.right();
if (right instanceof FinishExpr) {
reducerS.push((FinishExpr) f.right());
}
}
}
if (n instanceof Return) {
Return f = (Return) n;
if (f.expr() instanceof FinishExpr) {
reducerS.push((FinishExpr) f.expr());
}
}
return this;
}
public Node leaveCall(Node old, Node n, NodeVisitor v) throws SemanticException {
if (n instanceof Async)
return visitAsync(old, (Async) n);
if (n instanceof AtStmt)
return visitAtStmt((AtStmt) n);
if (n instanceof AtExpr)
return visitAtExpr((AtExpr) n);
if (n instanceof Here_c)
return visitHere((Here_c) n);
if (n instanceof Next)
return visitNext((Next) n);
if (n instanceof Atomic)
return visitAtomic((Atomic) n);
if (n instanceof When)
return visitWhen((When) n);
if (n instanceof Finish)
return visitFinish((Finish) n);
if (n instanceof Offer)
return visitOffer((Offer) n);
if (n instanceof Return)
return visitReturn((Return) n);
if (n instanceof AtEach)
return visitAtEach((AtEach) n);
if (n instanceof Eval)
return visitEval((Eval) n);
if (n instanceof LocalDecl)
return visitLocalDecl((LocalDecl) n);
if (n instanceof Resume)
return visitResume((Resume) n);
return n;
}
private Expr visitAtExpr(AtExpr e) throws SemanticException {
return visitRemoteClosure(e, EVAL_AT, e.place());
}
Expr getPlace(Position pos, Expr place) throws SemanticException{
if (! ts.isImplicitCastValid(place.type(), ts.Place(), context())) {
throw new InternalCompilerError("The place argument of an \"at\" is not of type Place", place.position());
}
return place;
}
private Expr visitRemoteClosure(Closure c, Name implName, Expr place) throws SemanticException {
Position pos = c.position();
place = getPlace(pos, place);
List<TypeNode> typeArgs = Arrays.asList(new TypeNode[] { c.returnType() });
Position bPos = c.body().position();
ClosureDef cDef = c.closureDef().position(bPos);
// If in a clocked context, must capture implicit clock variable
// being added by the lowering phase.
if (!clockStack.isEmpty()) {
cDef.addCapturedVariable(clockStack.peek().localInstance());
}
Expr closure = nf.Closure(c, bPos)
.closureDef(cDef)
.type(cDef.classDef().asType());
Expr prof = getProfile(c.closureDef());
List<Expr> args = new ArrayList<Expr>(Arrays.asList(new Expr[] { place, closure, prof }));
Expr result = synth.makeStaticCall(pos, ts.Runtime(), implName,
typeArgs, args, c.type(), context());
return result;
}
private static CodeInstance<?> findEnclosingCode(CodeInstance<?> ci) {
if (ci instanceof AsyncInstance) {
return findEnclosingCode(((AsyncInstance) ci).methodContainer());
} else if (ci instanceof AtInstance) {
return findEnclosingCode(((AtInstance) ci).methodContainer());
}
return ci;
}
protected Expr getEndpoint(AtDef def) throws SemanticException {
Type t = ts.Endpoint();
List<Type> as = def.annotationsMatching(t);
for (Type at : as) {
// TODO: fail if more than 1 @Endpoint annotation
return getEndpointExpr(at);
}
return null;
}
protected Expr getEndpointExpr(Type at) throws SemanticException {
at = Types.baseType(at);
if (at instanceof X10ClassType) {
X10ClassType act = (X10ClassType) at;
if (0 < act.propertyInitializers().size()) {
return act.propertyInitializer(0);
}
}
return null;
}
protected Expr getProfile(X10Def def) throws SemanticException {
Type t = ts.Profile();
List<Type> as = def.annotationsMatching(t);
for (Type at : as) {
// TODO: fail if more than 1 @Profile annotation
return getProfileExpr(at);
}
return nodeFactory().NullLit(def.position()).type(typeSystem().Null());
}
protected Expr getProfileExpr(Type at) throws SemanticException {
at = Types.baseType(at);
if (at instanceof X10ClassType) {
X10ClassType act = (X10ClassType) at;
if (0 < act.propertyInitializers().size()) {
return act.propertyInitializer(0);
}
}
return nodeFactory().NullLit(at.position()).type(typeSystem().Null());
}
private Stmt atStmt(Position pos, Stmt at_body, Expr place,
List<VarInstance<? extends VarDef>> env, AtDef def) throws SemanticException {
place = getPlace(pos, place);
// try { at_body }
Block tryBlock = synth.toBlock(at_body);
List<Catch> catches = new ArrayList<Catch>();
{ // catch (e:CheckedThrowable) { Runtime.wrapAtChecked(e); }
Name catchFormalName = getTmp();
LocalDef catchFormalLocalDef = ts.localDef(pos, ts.NoFlags(), Types.ref(ts.CheckedThrowable()), catchFormalName);
Formal catchFormal = nf.Formal(pos, nf.FlagsNode(pos, ts.NoFlags()),
nf.CanonicalTypeNode(pos, ts.CheckedThrowable()), nf.Id(pos, catchFormalName)).localDef(catchFormalLocalDef);
Expr catchLocal = nf.Local(pos, nf.Id(pos, catchFormalName)).localInstance(catchFormalLocalDef.asInstance()).type(ts.Error());
Expr wrap = synth.makeStaticCall(pos, ts.Runtime(), Name.make("wrapAtChecked"), Collections.singletonList(catchLocal), ts.Exception(), context());
Block catchBlock = nf.Block(pos, nf.Eval(pos, wrap));
catches.add(nf.Catch(pos, catchFormal, catchBlock));
}
Block closure_body = synth.toBlock(nf.Try(pos, tryBlock, catches, null));
Closure closure = synth.makeClosure(at_body.position(), ts.Void(), closure_body, context());
closure.closureDef().setCapturedEnvironment(env);
CodeInstance<?> mi = findEnclosingCode(Types.get(closure.closureDef().methodContainer()));
closure.closureDef().setMethodContainer(Types.ref(mi));
Expr[] args;
Expr profile = getProfile(def);
Expr endpoint = getEndpoint(def);
if (null != endpoint) {
args = new Expr[] { place, closure, profile, endpoint };
} else {
args = new Expr[] { place, closure, profile };
}
List<Stmt> statements = new ArrayList<Stmt>();
Stmt run_at = nf.Eval(pos,
synth.makeStaticCall(pos, ts.Runtime(), RUN_AT,
Arrays.asList(args), ts.Void(),
context()));
statements.add(run_at);
// [DC] It seems this can sometimes be null, even though it ought not to be.
// I suspect some pass before this one is not filling it in, in some new code.
if (at_body.exceptions() != null) {
for (Type thrown : at_body.exceptions()) {
TypeNode thrown_node = nf.UnknownTypeNode(pos).typeRef(Types.ref(thrown));
//XTENLANG-3086 change from ts.CheckedThrowable() to ts.Runtime()
Expr pretendToThrow = synth.makeStaticCall(pos, ts.CheckedThrowable(), Name.make("pretendToThrow"), Collections.singletonList(thrown_node), Collections.<Expr>emptyList(), ts.Void(), context());
statements.add(nf.Eval(pos, pretendToThrow));
}
}
return nf.Block(pos, statements);
}
private Stmt visitAtStmt(AtStmt a) throws SemanticException {
Position pos = a.position();
// If in a clocked context, must capture implicit clock variable
// being added by the lowering phase.
List<VarInstance<? extends VarDef>> env = a.atDef().capturedEnvironment();
if (!clockStack.isEmpty()) {
env = new ArrayList<VarInstance<? extends VarDef>>(env);
env.add(clockStack.peek().localInstance());
}
return atStmt(pos, a.body(), a.place(), env, a.atDef());
}
private AtStmt toAtStmt(Stmt body) {
if ((body instanceof AtStmt)) {
return (AtStmt) body;
}
if (body instanceof Block) {
Block block = (Block) body;
if (block.statements().size()==1) {
body = block.statements().get(0);
if ((body instanceof AtStmt)) {
return (AtStmt) body;
}
}
}
return null;
}
private Async toAsync(Stmt body) {
if ((body instanceof Async)) {
return (Async) body;
}
if (body instanceof Block) {
Block block = (Block) body;
if (block.statements().size()==1) {
body = block.statements().get(0);
if ((body instanceof Async)) {
return (Async) body;
}
}
}
return null;
}
private List<Expr> clocks(boolean clocked, List<Expr> clocks) {
if (! clocked)
return clocks;
if (clocks == null)
clocks = new ArrayList<Expr>();
clocks.add(clockStack.peek());
return clocks;
}
// Begin asyncs
// rewrite @Uncounted async S, with special translation for @Uncounted async at (p) S.
private Stmt visitAsync(Node old, Async a) throws SemanticException {
List<Expr> clocks = clocks(a.clocked(), a.clocks());
Position pos = a.position();
X10Ext ext = (X10Ext) a.ext();
List<X10ClassType> refs = AnnotationUtils.annotationsNamed(a, REF);
List<VarInstance<? extends VarDef>> env = a.asyncDef().capturedEnvironment();
if (a.clocked()) {
env = new ArrayList<VarInstance<? extends VarDef>>(env);
env.add(clockStack.peek().localInstance());
}
if (isUncountedAsync(ts, a)) {
if (old instanceof Async)
return uncountedAsync(pos, a.body(), env);
}
if (old instanceof Async)
return async(pos, a.body(), clocks, refs, env);
Stmt specializedAsync = specializeAsync(a, null, a.body());
if (specializedAsync != null)
return specializedAsync;
return async(pos, a.body(), clocks, refs, env);
}
// Begin asyncs
// rewrite @Uncounted async S, with special translation for @Uncounted async at (p) S.
private Stmt visitAsyncPlace(Async a, Expr place, Stmt body, List<VarInstance<? extends VarDef>> env, Expr prof) throws SemanticException {
List<Expr> clocks = clocks(a.clocked(), a.clocks());
Position pos = a.position();
List<X10ClassType> refs = AnnotationUtils.annotationsNamed(a, REF);
if (a.clocked()) {
env = new ArrayList<VarInstance<? extends VarDef>>(env);
env.add(clockStack.peek().localInstance());
}
if (isUncountedAsync(ts, a)) {
return uncountedAsync(pos, body, place, env);
}
Stmt specializedAsync = specializeAsync(a, place, body);
if (specializedAsync != null)
return specializedAsync;
return async(pos, body, clocks, place, refs, env, prof);
}
// TODO: add more rules from SPMDcppCodeGenerator
private boolean isGloballyAvailable(Expr e) {
if (e instanceof Local)
return true;
return false;
}
public static boolean isUncountedAsync(TypeSystem ts, Async a) {
return AnnotationUtils.hasAnnotation(ts, a, UNCOUNTED);
}
/**
* Recognize the following pattern:
* <pre>
* @Immediate async at(p) {
* r(i) ^= v;
* }
* </pre>
* where <tt>p: Place</tt>, <tt>r: Rail[T]!p</tt>, <tt>i:Int</tt>, and <tt>v:T</tt>,
* and compile it into an optimized remote operation.
* @param a the async statement
* @return an invocation of the remote operation, or null if no match
* @throws SemanticException
* TODO: move into a separate pass!
*/
private Stmt specializeAsync(Async a, Expr p, Stmt body) throws SemanticException {
if (!AnnotationUtils.hasAnnotation(ts, a, IMMEDIATE))
return null;
if (a.clocks().size() != 0)
return null;
if (body instanceof Block) {
List<Stmt> stmts = ((Block) body).statements();
if (stmts.size() != 1)
return null;
body = stmts.get(0);
}
if (!(body instanceof Eval))
return null;
Expr e = ((Eval) body).expr();
if (!(e instanceof SettableAssign))
return null;
SettableAssign sa = (SettableAssign) e;
if (sa.operator() != Assign.BIT_XOR_ASSIGN)
return null;
List<Expr> is = sa.index();
if (is.size() != 1)
return null;
Expr i = is.get(0);
if (p instanceof X10New) {
// TODO: make sure we calling the place constructor
// TODO: decide between rail and place-local handle
X10New n = (X10New) p;
Expr q = n.arguments().get(0);
Expr r = sa.array();
Expr v = sa.right();
if (/*!isGloballyAvailable(r) || */!isGloballyAvailable(i) || !isGloballyAvailable(v))
return null;
/* List<Type> ta = ((X10ClassType) X10TypeMixin.baseType(r.type())).typeArguments();
if (!v.type().isLong() || !ts.isRailOf(r.type(), ts.Long()))
return null;
if (!PlaceChecker.isAtPlace(r, p, xContext()))
return null;
*/
ClassType RemoteOperation = (ClassType) ts.forName(REMOTE_OPERATION);
Position pos = a.position();
List<Expr> args = new ArrayList<Expr>();
Expr p1 = (Expr) leaveCall(null, q, this);
args.add(p1);
args.add((Expr) leaveCall(null, r, this));
args.add((Expr) leaveCall(null, i, this));
args.add((Expr) leaveCall(null, v, this));
Stmt alt = nf.Eval(pos, synth.makeStaticCall(pos, RemoteOperation, XOR, args, ts.Void(), context()));
Expr cond = nf.Binary(pos, q, X10Binary_c.EQ, call(pos, HERE_INT, ts.Int())).type(ts.Boolean());
Stmt cns = a.body();
return nf.If(pos, cond, cns, alt);
} else {
Expr r = sa.array();
Expr v = sa.right();
if (/*!isGloballyAvailable(r) || */!isGloballyAvailable(i) || !isGloballyAvailable(v))
return null;
/* List<Type> ta = ((X10ClassType) X10TypeMixin.baseType(r.type())).typeArguments();
if (!v.type().isLong() || !ts.isRailOf(r.type(), ts.Long()))
return null;
if (!PlaceChecker.isAtPlace(r, p, xContext()))
return null;
*/
ClassType RemoteOperation = (ClassType) ts.forName(REMOTE_OPERATION);
Position pos = a.position();
List<Expr> args = new ArrayList<Expr>();
Expr p1 = (Expr) leaveCall(null, p, this);
args.add(p1);
args.add((Expr) leaveCall(null, r, this));
args.add((Expr) leaveCall(null, i, this));
args.add((Expr) leaveCall(null, v, this));
Stmt alt = nf.Eval(pos, synth.makeStaticCall(pos, RemoteOperation, XOR, args, ts.Void(), context()));
Expr cond = nf.Binary(pos, p, X10Binary_c.EQ, call(pos, HOME, ts.Place())).type(ts.Boolean());
Stmt cns = a.body();
return nf.If(pos, cond, cns, alt);
}
}
private Stmt async(Position pos, Stmt body, List<Expr> clocks, Expr place, List<X10ClassType> annotations,
List<VarInstance<? extends VarDef>> env, Expr prof) throws SemanticException {
if (ts.isImplicitCastValid(place.type(), ts.GlobalRef(), context())) {
place = synth.makeFieldAccess(pos,place, ts.homeName(), context());
}
if (clocks.size() == 0)
return async(pos, body, place, annotations, env, prof);
Type clockRailType = Types.makeArrayRailOf(ts.Clock(), pos);
Tuple clockRail = (Tuple) nf.Tuple(pos, clocks).type(clockRailType);
return makeAsyncBody(pos, new ArrayList<Expr>(Arrays.asList(new Expr[] { place, clockRail })),
new ArrayList<Type>(Arrays.asList(new Type[] { ts.Place(), clockRailType})),
body, annotations, env, prof);
}
private Stmt async(Position pos, Stmt body, Expr place, List<X10ClassType> annotations,
List<VarInstance<? extends VarDef>> env, Expr prof) throws SemanticException {
List<Expr> l = new ArrayList<Expr>(1);
l.add(place);
List<Type> t = new ArrayList<Type>(1);
t.add(ts.Place());
return makeAsyncBody(pos, l, t, body, annotations, env, prof);
}
private Stmt async(Position pos, Stmt body, List<Expr> clocks, List<X10ClassType> annotations,
List<VarInstance<? extends VarDef>> env) throws SemanticException {
if (clocks.size() == 0)
return async(pos, body, annotations, env);
Type clockRailType = Types.makeArrayRailOf(ts.Clock(), pos);
Tuple clockRail = (Tuple) nf.Tuple(pos, clocks).type(clockRailType);
return makeAsyncBody(pos, new ArrayList<Expr>(Arrays.asList(new Expr[] { clockRail })),
new ArrayList<Type>(Arrays.asList(new Type[] { clockRailType})), body,
annotations, env, null);
}
private Stmt async(Position pos, Stmt body, List<X10ClassType> annotations,
List<VarInstance<? extends VarDef>> env) throws SemanticException {
return makeAsyncBody(pos, new LinkedList<Expr>(),
new LinkedList<Type>(), body, annotations, env, null);
}
private Stmt makeAsyncBody(Position pos, List<Expr> exprs, List<Type> types,
Stmt async_body, List<X10ClassType> annotations,
List<VarInstance<? extends VarDef>> env, Expr prof) throws SemanticException {
if (annotations == null)
annotations = new ArrayList<X10ClassType>(1);
annotations.add((X10ClassType) ts.systemResolver().findOne(ASYNC_CLOSURE));
Stmt closure_body = async_body;
// [DC] don't add the try/catch if this is a CUDA kernel
// rationale: CUDA kernels may not throw exceptions (although this is not enforced)
// in particular, it is hard to think of why an interop exception would emerge from a CUDA kernel
// So, the lack of enforcement is very unlikely to create a noticable problem.
if (!(async_body instanceof CUDAKernel)) {
// try { async_body }
Block tryBlock = synth.toBlock(async_body);
List<Catch> catches = new ArrayList<Catch>();
{ // catch (e:Error) { throw e; }
Name catchFormalName = getTmp();
LocalDef catchFormalLocalDef = ts.localDef(pos, ts.NoFlags(), Types.ref(ts.Error()), catchFormalName);
Formal catchFormal = nf.Formal(pos, nf.FlagsNode(pos, ts.NoFlags()),
nf.CanonicalTypeNode(pos, ts.Error()), nf.Id(pos, catchFormalName)).localDef(catchFormalLocalDef);
Expr catchLocal = nf.Local(pos, nf.Id(pos, catchFormalName)).localInstance(catchFormalLocalDef.asInstance()).type(ts.Error());
Block catchBlock = nf.Block(pos, nf.Throw(pos, catchLocal));
catches.add(nf.Catch(pos, catchFormal, catchBlock));
}
{ // catch (e:CheckedThrowable) { throw Exception.ensureException(e); }
Name catchFormalName = getTmp();
LocalDef catchFormalLocalDef = ts.localDef(pos, ts.NoFlags(), Types.ref(ts.CheckedThrowable()), catchFormalName);
Formal catchFormal = nf.Formal(pos, nf.FlagsNode(pos, ts.NoFlags()),
nf.CanonicalTypeNode(pos, ts.CheckedThrowable()), nf.Id(pos, catchFormalName)).localDef(catchFormalLocalDef);
Expr catchLocal = nf.Local(pos, nf.Id(pos, catchFormalName)).localInstance(catchFormalLocalDef.asInstance()).type(ts.Error());
Expr wrap = synth.makeStaticCall(pos, ts.Exception(), Name.make("ensureException"), Collections.singletonList(catchLocal), ts.Exception(), context());
Block catchBlock = nf.Block(pos, nf.Throw(pos, wrap));
catches.add(nf.Catch(pos, catchFormal, catchBlock));
}
closure_body = nf.Try(pos, tryBlock, catches, null);
}
Closure closure = synth.makeClosure(async_body.position(), ts.Void(), synth.toBlock(closure_body), context(), annotations);
closure.closureDef().setCapturedEnvironment(env);
CodeInstance<?> mi = findEnclosingCode(Types.get(closure.closureDef().methodContainer()));
closure.closureDef().setMethodContainer(Types.ref(mi));
exprs.add(closure);
types.add(closure.closureDef().asType());
if (prof != null) {
exprs.add(prof);
types.add(prof.type());
}
Stmt result = nf.Eval(pos,
synth.makeStaticCall(pos, ts.Runtime(), RUN_ASYNC, exprs,
ts.Void(), types, context()));
return result;
}
private Stmt uncountedAsync(Position pos, Stmt body, Expr place,
List<VarInstance<? extends VarDef>> env) throws SemanticException {
List<Expr> l = new ArrayList<Expr>(1);
l.add(place);
List<Type> t = new ArrayList<Type>(1);
t.add(ts.Place());
return makeUncountedAsyncBody(pos, l, t, body, env);
}
private Stmt uncountedAsync(Position pos, Stmt body,
List<VarInstance<? extends VarDef>> env) throws SemanticException {
return makeUncountedAsyncBody(pos, new LinkedList<Expr>(),
new LinkedList<Type>(), body, env);
}
private Stmt makeUncountedAsyncBody(Position pos, List<Expr> exprs, List<Type> types, Stmt body,
List<VarInstance<? extends VarDef>> env) throws SemanticException {
Closure closure = synth.makeClosure(body.position(), ts.Void(), synth.toBlock(body), context());
closure.closureDef().setCapturedEnvironment(env);
CodeInstance<?> mi = findEnclosingCode(Types.get(closure.closureDef().methodContainer()));
closure.closureDef().setMethodContainer(Types.ref(mi));
exprs.add(closure);
types.add(closure.closureDef().asType());
Stmt result = nf.Eval(pos,
synth.makeStaticCall(pos, ts.Runtime(), RUN_UNCOUNTED_ASYNC, exprs,
ts.Void(), types, context()));
return result;
}
// end Async
// here -> Runtime.home()
private Expr visitHere(Here_c h) throws SemanticException {
Position pos = h.position();
return call(pos, HOME, ts.Place());
}
// next; -> Clock.advanceAll(); (deprecated)
private Stmt visitNext(Next n) throws SemanticException {
Position pos = n.position();
return nf.Eval(pos, synth.makeStaticCall(pos, ts.Clock(), NEXT, ts.Void(), context()));
}
// resume; -> Clock.resumeAll(); (deprecated)
private Stmt visitResume(Resume n) throws SemanticException {
Position pos = n.position();
return nf.Eval(pos, synth.makeStaticCall(pos, ts.Clock(), RESUME, ts.Void(), context()));
}
// atomic S; -> try { Runtime.enterAtomic(); S } finally { Runtime.exitAtomic(); }
private Stmt visitAtomic(Atomic a) throws SemanticException {
Position pos = a.position();
Block tryBlock = nf.Block(pos, nf.Eval(pos, call(pos, ENTER_ATOMIC, ts.Void())), a.body());
Block finallyBlock = nf.Block(pos, nf.Eval(pos, call(pos, EXIT_ATOMIC, ts.Void())));
return nf.Try(pos, tryBlock, Collections.<Catch>emptyList(), finallyBlock);
}
private Stmt wrap(Position pos, Stmt s) {
return s.reachable() ? nf.Block(pos, s, nf.Break(pos)) : s;
}
protected Expr getLiteral(Position pos, Type type, boolean val) {
type = Types.baseType(type);
if (ts.isBoolean(type)) {
Type t = ts.Boolean();
t = Types.addSelfBinding(t, val ? ts.TRUE() : ts.FALSE());
return nf.BooleanLit(pos, val).type(t);
} else
throw new InternalCompilerError(pos, "Unknown literal type: "+type);
}
// when(E1) S1 or(E2) S2...; ->
// Runtime.ensureNotInAtomic();
// try { Runtime.enterAtomic();
// while (true) { if (E1) { S1; break; } if (E2) { S2; break; } ... Runtime.awaitAtomic(); }
// finally { Runtime.exitAtomic(); }
private Stmt visitWhen(When w) throws SemanticException {
Position pos = w.position();
Block body = nf.Block(pos, nf.If(pos, w.expr(), wrap(pos, w.stmt())));
for(int i=0; i<w.stmts().size(); i++) {
body = body.append(nf.If(pos, (Expr) w.exprs().get(i), wrap(pos, (Stmt) w.stmts().get(i))));
}
body = body.append(nf.Eval(pos, call(pos, AWAIT_ATOMIC, ts.Void())));
Block tryBlock = nf.Block(pos,
nf.Eval(pos, call(pos, ENTER_ATOMIC, ts.Void())),
nf.While(pos, getLiteral(pos, ts.Boolean(), true), body));
Block finallyBlock = nf.Block(pos, nf.Eval(pos, call(pos, EXIT_ATOMIC, ts.Void())));
return nf.Block(pos,
nf.Eval(pos, call(pos, ENSURE_NOT_IN_ATOMIC, ts.Void())),
nf.Try(pos,
tryBlock, Collections.<Catch>emptyList(),
finallyBlock));
}
protected Expr call(Position pos, Name name, Type returnType) throws SemanticException {
return synth.makeStaticCall(pos, ts.Runtime(), name, returnType, context());
}
protected Expr call(Position pos, Name name, Expr arg, Type returnType) throws SemanticException {
return synth.makeStaticCall(pos, ts.Runtime(), name, Collections.singletonList(arg), returnType, context());
}
/**
* Recognize the following pattern:
* <pre>
* @Immediate finish S;
* </pre>
* where <tt>S</tt> is any statement,
* and compile it into S followed by an optimized remote fence operation.
* @param f the finish statement
* @return a block consisting of S followed by the invocation of a remote fence operation, or null if no match
* @throws SemanticException
* TODO: move into a separate pass!
*/
private Stmt specializeFinish(Finish f) throws SemanticException {
if (!AnnotationUtils.hasAnnotation(ts, f, IMMEDIATE))
return null;
Position pos = f.position();
ClassType target = (ClassType) ts.forName(REMOTE_OPERATION);
List<Expr> args = new ArrayList<Expr>();
return nf.Block(pos, f.body(), nf.Eval(pos, synth.makeStaticCall(pos, target, FENCE, args, ts.Void(), context())));
}
private int getPatternFromAnnotation(AnnotationNode a){
Ref<? extends Type> r = a.annotationType().typeRef();
X10ParsedClassType xpct = (X10ParsedClassType) r.getCached();
List<Expr> allProperties = xpct.propertyInitializers();
Expr pattern = allProperties.get(3);
if (pattern instanceof IntLit_c) {
return (int) ((IntLit_c) pattern).value();
}
return 0;
}
/**
* Recognize the following pattern:
* @FinishAsync(,,,"local") which means all asyncs in this finish are in the same place as finish
* @param f
* @return a method call expression that invokes "startLocalFinish"
* @throws SemanticException
*/
private Expr specializedFinish2(Finish f) throws SemanticException {
Position pos = f.position();
int p=0;
Type annotation = ts.systemResolver().findOne(QName.make("x10.compiler.FinishAsync"));
if (!((X10Ext) f.ext()).annotationMatching(annotation).isEmpty()) {
List<AnnotationNode> allannots = ((X10Ext)(f.ext())).annotations();
AnnotationNode a = null;
int p1 = 0;
int p2 = 0;
if(allannots.size()>0){
if (allannots.size() > 1) {
boolean isConsistent = true;
for(int i=0;i<allannots.size()-1;i++){
p1 = getPatternFromAnnotation(allannots.get(i));
p2 = getPatternFromAnnotation(allannots.get(i+1));
if(p1 != p2){
isConsistent = false;
break;
}
}
if(!isConsistent){
reporter.report(0,"WARNING:compiler inferes different annotations from what the programer sets in "+job.source().name());
if(reporter.should_report("verbose", 1)){
reporter.report(5,"\tcompiler inferes "+p1);
reporter.report(5,"\tprogrammer annotates "+p2);
}
}
}
a = allannots.get(allannots.size()-1);
if(reporter.should_report("", 1))
reporter.report(1,a.toString());
p = getPatternFromAnnotation(a);
}else{
reporter.report(0,"annotation is not correct "+ allannots.size());
}
}
Type atype = ts.systemResolver().findOne(PRAGMA);
List<X10ClassType> atypes = ((X10Ext) f.ext()).annotationMatching(atype);
if (!atypes.isEmpty()) {
return call(pos, START_FINISH, atypes.get(0).propertyInitializer(0), ts.FinishState());
}
switch(p){
case 1:return call(pos, START_LOCAL_FINISH, ts.FinishState());
case 2:return call(pos, START_SIMPLE_FINISH, ts.FinishState());
//TODO:more patterns can be filled here
default:return call(pos, START_FINISH, ts.FinishState());
}
}
// finish S; ->
// {
// Runtime.ensureNotInAtomic();
// val fresh = Runtime.startFinish();
// try { S; }
// catch (t:Throwable) { Runtime.pushException(t); throw new Exception(); }
// finally { Runtime.stopFinish(fresh); }
// }
private Stmt visitFinish(Finish f) throws SemanticException {
Position pos = f.position();
Name tmp = getTmp();
Stmt specializedFinish = specializeFinish(f);
if (specializedFinish != null)
return specializedFinish;
// TODO: merge with the call() function
Type catchType = ts.CheckedThrowable();
MethodInstance mi = ts.findMethod(ts.Runtime(),
ts.MethodMatcher(ts.Runtime(), PUSH_EXCEPTION, Collections.singletonList(catchType), context()));
LocalDef lDef = ts.localDef(pos, ts.NoFlags(), Types.ref(catchType), tmp);
Formal formal = nf.Formal(pos, nf.FlagsNode(pos, ts.NoFlags()),
nf.CanonicalTypeNode(pos, catchType), nf.Id(pos, tmp)).localDef(lDef);
Expr local = nf.Local(pos, nf.Id(pos, tmp)).localInstance(lDef.asInstance()).type(catchType);
Expr call = nf.X10Call(pos, nf.CanonicalTypeNode(pos, ts.Runtime()),
nf.Id(pos, PUSH_EXCEPTION), Collections.<TypeNode>emptyList(),
Collections.singletonList(local)).methodInstance(mi).type(ts.Void());
Throw thr = throwException(pos);
Expr startCall = specializedFinish2(f);
Context xc = context();
final Name varName = xc.getNewVarName();
final Type type = ts.FinishState();
final LocalDef li = ts.localDef(pos, ts.Final(), Types.ref(type), varName);
final Id varId = nf.Id(pos, varName);
final LocalDecl ld = nf.LocalDecl(pos, nf.FlagsNode(pos, ts.Final()), nf.CanonicalTypeNode(pos, type), varId, startCall).localDef(li).type(nf.CanonicalTypeNode(pos, type));
final Local ldRef = (Local) nf.Local(pos, varId).localInstance(li.asInstance()).type(type);
Block tryBlock = nf.Block(pos, f.body());
Catch catchBlock = nf.Catch(pos, formal, nf.Block(pos, nf.Eval(pos, call), thr));
Block finallyBlock = nf.Block(pos, nf.Eval(pos, call(pos, STOP_FINISH, ldRef, ts.Void())));
Try tcfBlock = nf.Try(pos, tryBlock, Collections.singletonList(catchBlock), finallyBlock);
// propagate async initialization info to backend
X10Ext_c ext = (X10Ext_c) f.ext();
if (ext.initVals != null) {
tcfBlock = (Try)((X10Ext_c)tcfBlock.ext()).asyncInitVal(ext.initVals);
}
return nf.Block(pos,
nf.Eval(pos, call(pos, ENSURE_NOT_IN_ATOMIC, ts.Void())),
ld,
tcfBlock);
}
// Generates a throw of a new Exception().
private Throw throwException(Position pos) throws SemanticException {
Type re = ts.Exception();
X10ConstructorInstance ci = ts.findConstructor(re, ts.ConstructorMatcher(re, Collections.<Type>emptyList(), context()));
Expr newRE = nf.New(pos, nf.CanonicalTypeNode(pos, re), Collections.<Expr>emptyList()).constructorInstance(ci).type(re);
return nf.Throw(pos, newRE);
}
// x = finish (R) S; ->
// {
// val fresh = Runtime.startCollectingFinish(R);
// try { S; }
// catch (t:Throwable) { Runtime.pushException(t); throw new Exception(); }
// finally { x = Runtime.stopCollectingFinish(fresh); }
// }
private Stmt visitFinishExpr(Assign n, LocalDecl l, Return r) throws SemanticException {
FinishExpr f = null;
if ((l==null) && (n!=null)&& (r == null)) {
f = (FinishExpr) n.right();
}
if ((n==null) && (l!=null)&& (r==null)) {
f = (FinishExpr) l.init();
}
if ((n==null) && (l==null)&& (r!=null)) {
f = (FinishExpr) r.expr();
}
Position pos = f.position();
Expr reducer = f.reducer();
// Begin Try Block Code
Type reducerType = reducer.type();
if (reducerType instanceof ConstrainedType) {
ConstrainedType ct = (ConstrainedType) reducerType;
reducerType = Types.baseType(Types.get(ct.baseType()));
}
// reducerType is "Reducible[T]", and reducerTarget is "T"
// Parse out T
Type reducerTarget = Types.reducerType(reducerType);
assert reducerTarget!=null;
Call myCall = synth.makeStaticCall(pos, ts.Runtime(), START_COLLECTING_FINISH, Collections.<TypeNode>singletonList(nf.CanonicalTypeNode(pos, reducerTarget)), Collections.singletonList(reducer), ts.Void(), Collections.singletonList(reducerType), context());
Context xc = context();
final Name varName = xc.getNewVarName();
final Type type = ts.FinishState();
final LocalDef li = ts.localDef(pos, ts.Final(), Types.ref(type), varName);
final Id varId = nf.Id(pos, varName);
final LocalDecl s1 = nf.LocalDecl(pos, nf.FlagsNode(pos, ts.Final()), nf.CanonicalTypeNode(pos, type), varId, myCall).localDef(li).type(nf.CanonicalTypeNode(pos, type));
final Local ldRef = (Local) nf.Local(pos, varId).localInstance(li.asInstance()).type(type);
Block tryBlock = nf.Block(pos,f.body());
// Begin catch block
Name tmp2 = getTmp();
Type catchType = ts.CheckedThrowable();
MethodInstance mi = ts.findMethod(ts.Runtime(),
ts.MethodMatcher(ts.Runtime(), PUSH_EXCEPTION, Collections.singletonList(catchType), context()));
LocalDef lDef = ts.localDef(pos, ts.NoFlags(), Types.ref(catchType), tmp2);
Formal formal = nf.Formal(pos, nf.FlagsNode(pos, ts.NoFlags()),
nf.CanonicalTypeNode(pos, catchType), nf.Id(pos, tmp2)).localDef(lDef);
Expr local = nf.Local(pos, nf.Id(pos, tmp2)).localInstance(lDef.asInstance()).type(catchType);
Expr call = nf.X10Call(pos, nf.CanonicalTypeNode(pos, ts.Runtime()),
nf.Id(pos, PUSH_EXCEPTION), Collections.<TypeNode>emptyList(),
Collections.singletonList(local)).methodInstance(mi).type(ts.Void());
Throw thr = throwException(pos);
Catch catchBlock = nf.Catch(pos, formal, nf.Block(pos, nf.Eval(pos, call), thr));
// Begin finally block
Stmt returnS = null;
Call staticCall = synth.makeStaticCall(pos, ts.Runtime(), STOP_COLLECTING_FINISH, Collections.<TypeNode>singletonList(nf.CanonicalTypeNode(pos, reducerTarget)), Collections.<Expr>singletonList(ldRef), reducerTarget, Collections.<Type>singletonList(type), context());
if ((l==null) && (n!=null)&& (r==null)) {
Expr left = n.left().type(reducerTarget);
Expr b = synth.makeAssign(pos, left, Assign.ASSIGN, staticCall, xc);
returnS = nf.Eval(pos, b);
}
if ((n==null) && (l!=null) && (r==null)) {
Expr local2 = nf.Local(pos, l.name()).localInstance(l.localDef().asInstance()).type(reducerTarget);
Expr b = synth.makeAssign(pos, local2, Assign.ASSIGN, staticCall, xc);
returnS = nf.Eval(pos, b);
}
if ((n==null) && (l==null) && (r!=null)) {
returnS = nf.X10Return(pos, staticCall, true);
}
Block finalBlock = nf.Block(pos, returnS);
if(reducerS.size()>0) reducerS.pop();
return nf.Block(pos, s1, nf.Try(pos, tryBlock, Collections.singletonList(catchBlock), finalBlock));
}
// offer e ->
// x10.lang.Runtime.offer(e);
private Stmt visitOffer(Offer n) throws SemanticException {
Position pos = n.position();
Expr offerTarget = n.expr();
Type expectType = null;
if(reducerS.size()>0) {
FinishExpr f = reducerS.peek();
Expr reducer = f.reducer();
Type reducerType = reducer.type();
if (reducerType instanceof ConstrainedType) {
ConstrainedType ct = (ConstrainedType) reducerType;
reducerType = Types.baseType(Types.get(ct.baseType()));
}
X10ParsedClassType reducerTypeWithGenericType = null;
Type thisType = reducerType;
while(thisType != null) {
//First check the reducerType itself is a reducible or not;
//If not, it should be a class that implements reducible
if(ts.isReducible(((ClassType)thisType).def().asType())){
//generic type case
reducerTypeWithGenericType = (X10ParsedClassType) thisType;
break;
}
else{
//implement interface case
for (Type t : ts.interfaces(thisType)) {
t = Types.baseType(t);
ClassType baseType = ((ClassType) t).def().asType();
if(ts.isReducible(baseType)){
reducerTypeWithGenericType = (X10ParsedClassType) t;
break;
}
}
}
thisType = ts.superClass(thisType);
}
assert(reducerTypeWithGenericType != null);
//because Reducible type only has one argument, we could take it directly
expectType = reducerTypeWithGenericType.typeArguments().get(0);
}
else {
expectType = offerTarget.type();
}
CanonicalTypeNode CCE = nf.CanonicalTypeNode(pos, expectType);
TypeNode reducerA = (TypeNode) CCE;
Expr newOfferTarget = nf.X10Cast(pos, reducerA, offerTarget,Converter.ConversionType.CHECKED).type(reducerA.type());
Call call = synth.makeStaticCall(pos, ts.Runtime(), OFFER, Collections.singletonList(offerTarget), ts.Void(), Collections.singletonList(expectType), context());
Stmt offercall = nf.Eval(pos, call);
return offercall;
}
//handle finishR in return stmt:
private Stmt visitReturn(Return n) throws SemanticException {
if (n.expr() instanceof FinishExpr) {
Stmt returnS = visitFinishExpr(null,null,n);
return returnS;
}
return n;
}
private Stmt visitLocalDecl(LocalDecl n) throws SemanticException {
if (n.init() instanceof FinishExpr) {
Position pos = n.position();
ArrayList<Stmt> sList = new ArrayList<Stmt>();
sList.add(n.init(null));
Stmt s = visitFinishExpr(null, n,null);
sList.add(s);
return nf.StmtSeq(pos, sList);
}
return n;
}
// ateach (p in D) S; ->
// { Runtime.ensureNotInAtomic(); val d = D.dist; for (p in d.places()) async (p) for (pt in d|here) async S; }
private Stmt visitAtEach(AtEach a) throws SemanticException {
Position pos = a.position();
Position bpos = a.body().position();
Name tmp = getTmp();
Expr domain = a.domain();
Type dType = domain.type();
if (ts.isX10DistArray(dType)) {
domain = altsynth.createFieldRef(pos, domain, DIST);
dType = domain.type();
}
LocalDef lDef = ts.localDef(pos, ts.Final(), Types.ref(dType), tmp);
LocalDecl local = nf.LocalDecl(pos, nf.FlagsNode(pos, ts.Final()),
nf.CanonicalTypeNode(pos, dType), nf.Id(pos, tmp), domain).localDef(lDef);
X10Formal formal = (X10Formal) a.formal();
Type fType = formal.type().type();
assert (ts.isPoint(fType));
assert (ts.isDistribution(dType));
// Have to desugar some newly-created nodes
Type pType = ts.Place();
MethodInstance rmi = ts.findMethod(dType,
ts.MethodMatcher(dType, RESTRICTION, Collections.singletonList(pType), context()));
Expr here = visitHere(nf.Here(bpos));
Expr dAtPlace = nf.Call(bpos,
nf.Local(pos, nf.Id(pos, tmp)).localInstance(lDef.asInstance()).type(dType),
nf.Id(bpos, RESTRICTION),
here).methodInstance(rmi).type(rmi.returnType());
Expr here1 = visitHere(nf.Here(bpos));
List<VarInstance<? extends VarDef>> env = a.atDef().capturedEnvironment();
Stmt body = async(a.body().position(), a.body(), a.clocks(), here1, null, env, nf.NullLit(bpos).type(ts.Null()));
Stmt inner = nf.ForLoop(pos, formal, dAtPlace, body).locals(formal.explode(this));
MethodInstance pmi = ts.findMethod(dType,
ts.MethodMatcher(dType, PLACES, Collections.<Type>emptyList(), context()));
Expr places = nf.Call(bpos,
nf.Local(pos, nf.Id(pos, tmp)).localInstance(lDef.asInstance()).type(dType),
nf.Id(bpos, PLACES)).methodInstance(pmi).type(pmi.returnType());
Name pTmp = getTmp();
LocalDef pDef = ts.localDef(pos, ts.Final(), Types.ref(pType), pTmp);
Formal pFormal = nf.Formal(pos, nf.FlagsNode(pos, ts.Final()),
nf.CanonicalTypeNode(pos, pType), nf.Id(pos, pTmp)).localDef(pDef);
List<VarInstance<? extends VarDef>> env1 = new ArrayList<VarInstance<? extends VarDef>>(env);
removeLocalInstance(env1, formal.localDef().asInstance());
for (int i = 0; i < formal.localInstances().length; i++) {
removeLocalInstance(env1, formal.localInstances()[i].asInstance());
}
env1.add(lDef.asInstance());
Stmt body1 = async(bpos, inner, a.clocks(),
nf.Local(bpos, nf.Id(bpos, pTmp)).localInstance(pDef.asInstance()).type(pType),
null, env1, nf.NullLit(bpos).type(ts.Null()));
Stmt outer = nf.ForLoop(pos, pFormal, places, body1);
// TODO: Instead of creating ForLoop's and then removing them,
// change the code above to create simple For's in the first place.
ForLoopOptimizer flo = new ForLoopOptimizer(job, ts, nf);
For newLoop = (For)outer.visit(((ContextVisitor)flo.begin()).context(context()));
return nf.Block(pos,
nf.Eval(pos, call(pos, ENSURE_NOT_IN_ATOMIC, ts.Void())),
local,
newLoop);
}
private boolean removeLocalInstance(List<VarInstance<? extends VarDef>> env, VarInstance<? extends VarDef> li) {
VarInstance<? extends VarDef> match = null;
for (VarInstance<? extends VarDef> vi : env) {
if (vi.def() == li.def())
match = vi;
}
if (match == null)
return false;
return env.remove(match);
}
private Stmt visitEval(Eval n) throws SemanticException {
Position pos = n.position();
if ((n.expr() instanceof Assign)&&(flag==1)) {
Assign f = (Assign) n.expr();
Expr right = f.right();
if (right instanceof FinishExpr)
return visitFinishExpr(f, null,null);
}
return n;
}
}