/*
* 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.compiler.ws.codegen;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import polyglot.ast.Assign;
import polyglot.ast.Binary;
import polyglot.ast.Call;
import polyglot.ast.Catch;
import polyglot.ast.Expr;
import polyglot.ast.Formal;
import polyglot.ast.LocalDecl;
import polyglot.ast.MethodDecl;
import polyglot.ast.New;
import polyglot.ast.NodeFactory;
import polyglot.ast.Receiver;
import polyglot.ast.Special;
import polyglot.ast.Stmt;
import polyglot.ast.Try;
import polyglot.ast.TypeNode;
import polyglot.frontend.Job;
import polyglot.types.ClassDef;
import polyglot.types.ClassType;
import polyglot.types.Context;
import polyglot.types.FieldDef;
import polyglot.types.Flags;
import polyglot.types.MethodDef;
import polyglot.types.Name;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.TypeSystem;
import polyglot.types.Types;
import polyglot.util.Pair;
import polyglot.util.Position;
import x10.ast.AnnotationNode;
import x10.ast.ClosureCall;
import x10.ast.X10Call;
import x10.ast.X10MethodDecl;
import x10.compiler.ws.util.WSUtil;
import x10.types.MethodInstance;
import x10.types.X10ClassDef;
import x10.types.X10ClassType;
import x10.types.X10MethodDef;
import x10.types.checker.PlaceChecker;
import x10.util.Synthesizer;
import x10.util.synthesizer.ClassSynth;
import x10.util.synthesizer.CodeBlockSynth;
import x10.util.synthesizer.ConstructorSynth;
import x10.util.synthesizer.FieldSynth;
import x10.util.synthesizer.InstanceCallSynth;
import x10.util.synthesizer.MethodSynth;
import x10.util.synthesizer.NewInstanceSynth;
import x10.util.synthesizer.NewLocalVarSynth;
import x10.util.synthesizer.SuperCallSynth;
/**
* @author Haichuan
*
* All Work-Stealing Code stateless synthesizer
*
* createXXX : create field/method/class
* genXXX: generate expression, stmt
* transXXX: transform a stmt to a code block
*
*
*/
public class WSSynthesizer {
static final protected Position compilerPos = Position.COMPILER_GENERATED;
static final protected Name REMAP = Name.make("remap");
static final protected Name FAST = Name.make("fast");
static final protected Name PUSH = Name.make("push");
static final protected Name POLL = Name.make("poll");
static final protected Name RESUME = Name.make("resume");
static final protected Name BACK = Name.make("back");
static final protected Name MOVE = Name.make("move");
static final protected Name RETHROW = Name.make("rethrow");
static final protected Name CAUGHT = Name.make("caught");
static final protected Name RUN_ASYNC_AT = Name.make("runAsyncAt");
static final protected Name RUN_AT = Name.make("runAt");
static final protected Name WORKER = Name.make("worker");
static final protected Name FRAME = Name.make("frame");
static final protected Name PC = Name.make("_pc");
static final protected Name FF = Name.make("ff");
static final protected Name UP = Name.make("up");
static final protected Name ROOT_FINISH = Name.make("rootFinish");
static final protected Name RETURN_VALUE = Name.make("_returnV");
static final protected Name RETURN_FLAG = Name.make("_returnF");
static final protected Name ASYNCS = Name.make("asyncs");
static final protected Name REDIRECT = Name.make("redirect");
static final protected Name CONTINUE_LATER = Name.make("continueLater");
static final protected Name CONTINUE_NOW = Name.make("continueNow");
static final protected Name OPERATOR = ClosureCall.APPLY;
static final protected Name ENTER_ATOMIC = Name.make("enterAtomic");
static final protected Name EXIT_WHEN = Name.make("exitWSWhen");
static final protected Name ACCEPT = Name.make("accept");
static final protected Name RD = Name.make("rd"); //used in collecting-finish frame constructor
static final protected Name CF_RESULT_FAST = Name.make("fastResult");
static final protected Name CF_RESULT = Name.make("result");
//private IWSClassFrame classFrame;
private Synthesizer synth;
private NodeFactory nf;
private TypeSystem ts;
public WSSynthesizer(NodeFactory nf, TypeSystem ts){
//this.classFrame = classFrame;
this.nf = nf;
this.ts = ts;
this.synth = new Synthesizer(nf, ts);
}
public Position position(Position pos, String s) {
return new Position(pos.path(), pos.nameAndLineString() + s);
}
public ClassSynth createClassSynth(Job job, Context ct, Type superClassType,
X10ClassDef outClassDef, Flags flags, String className){
ClassSynth classSynth = new ClassSynth(job, nf, ct, position(outClassDef.position(), className), superClassType, className);
classSynth.setKind(ClassDef.MEMBER);
classSynth.setFlags(flags);
classSynth.setOuter(outClassDef);
return classSynth;
}
public MethodSynth createFastMethodSynth(ClassSynth classSynth, boolean isInline){
MethodSynth fastMSynth = classSynth.createMethod(classSynth.pos(), FAST.toString());
fastMSynth.setFlag(Flags.PUBLIC);
if (isInline){
//only set inline to inner frames, not top frames
fastMSynth.addAnnotation(genInlineAnnotation());
}
fastMSynth.addFormal(compilerPos, Flags.FINAL, ts.Worker(), WORKER.toString());
return fastMSynth;
}
public MethodSynth createResumeMethodSynth(ClassSynth classSynth){
MethodSynth resumeMSynth = classSynth.createMethod(classSynth.pos(), RESUME.toString());
resumeMSynth.setFlag(Flags.PUBLIC);
resumeMSynth.addFormal(compilerPos, Flags.FINAL, ts.Worker(), WORKER.toString());
return resumeMSynth;
}
public MethodSynth createBackMethodSynth(ClassSynth classSynth){
MethodSynth backMSynth = classSynth.createMethod(classSynth.pos(), BACK.toString());
backMSynth.setFlag(Flags.PUBLIC);
backMSynth.addFormal(compilerPos, Flags.FINAL, ts.Worker(), WORKER.toString());
backMSynth.addFormal(compilerPos, Flags.FINAL, ts.Frame(), FRAME.toString());
return backMSynth;
}
public ConstructorSynth createConstructorSynth(ClassSynth classSynth){
ConstructorSynth conSynth = classSynth.createConstructor(classSynth.pos());
conSynth.addAnnotation(genHeaderAnnotation());
return conSynth;
}
public void genCopyConstructors(ClassSynth classSynth){
}
/**
* Generate a remap method: "def remap() = new <the method type>(-1, this);"
* @param cDecl The glass
* @return the class with "remap" method inserted
* @throws SemanticException
*/
protected void genRemapMethod(ClassSynth classSynth, boolean isEmptyMethod) throws SemanticException {
Context ct = classSynth.getContext();
ClassType cType = classSynth.getDef().asType();
Type scType = PlaceChecker.AddIsHereClause(cType, ct);
MethodSynth methodSynth = classSynth.createMethod(classSynth.pos(), REMAP.toString());
//upcast new instance
Type upCastTargetType;
if(ts.isSubtype(cType, ts.FinishFrame())){
upCastTargetType = ts.FinishFrame();
}
else if(ts.isSubtype(cType, ts.RegularFrame())){
upCastTargetType = ts.RegularFrame();
}
else{
upCastTargetType = ts.Frame();
}
methodSynth.setReturnType(upCastTargetType);
if (isEmptyMethod) {
methodSynth.setFlag(Flags.PUBLIC.Abstract());
return;
}
methodSynth.setFlag(Flags.PUBLIC);
NewInstanceSynth niSynth = new NewInstanceSynth(nf, ct, compilerPos, cType);
niSynth.addArgument(ts.Int(), synth.intValueExpr(-1, compilerPos) );
niSynth.addArgument(scType, synth.thisRef(cType, compilerPos));
Expr castReturn = genUpcastCall(cType, upCastTargetType, niSynth.genExpr());
Stmt ret = nf.Return(compilerPos, castReturn);
CodeBlockSynth blockSynth = methodSynth.getMethodBodySynth(compilerPos);
blockSynth.addStmt(ret);
}
/**
* Generate a copy constructor:
* def this(Int, o:<this_type>!){
* super(-1, upcast[this_Type, superType]o);
* ...//all fiedls' copy
* }
* @param cDecl The class to add this copy constructor
* @param copyStmts statements besides super() call to copy fields. Could be null
* @return the classDecl with the copy constructor
* @throws SemanticException
*/
public void genCopyConstructor(ClassSynth classSynth) throws SemanticException{
Context ct = classSynth.getContext();
ClassDef cDef = classSynth.getClassDef();
Type cType = classSynth.getClassDef().asType();
Type ccType = PlaceChecker.AddIsHereClause(cType, ct);
Type sType = cDef.superType().get();
Type scType = PlaceChecker.AddIsHereClause(sType, ct);
ConstructorSynth conSynth = classSynth.createConstructor(compilerPos);
conSynth.setFlags(Flags.PROTECTED);
conSynth.addFormal(compilerPos, Flags.FINAL, ts.Int(), "x"); //a dummy int formal
Expr otherRef = conSynth.addFormal(compilerPos, Flags.FINAL, ccType, "o");
CodeBlockSynth conStmtsSynth = conSynth.createConstructorBody(compilerPos);
SuperCallSynth superCallSynth = conStmtsSynth.createSuperCall(compilerPos, cDef);
superCallSynth.addArgument(ts.Int(), synth.intValueExpr(-1, compilerPos));
Expr upCastOtherRef = genUpcastCall(cType, sType, otherRef);
superCallSynth.addArgument(scType, upCastOtherRef);
// now try to add fields copy directly
Receiver leftReceiver = synth.thisRef(cType, compilerPos); //this
for (FieldDef df : cDef.fields()) {
Name fieldName = df.name();
//Ingore RETURN_VALUE copy
if(fieldName.toString().equals(RETURN_VALUE.toString())
|| fieldName.toString().equals(RETURN_FLAG.toString())){
continue;
}
Stmt s = nf.Eval(compilerPos, synth.makeFieldToFieldAssign(compilerPos, leftReceiver, fieldName, otherRef,
fieldName, ct));
conStmtsSynth.addStmt(s);
}
}
/**
* Generate @Header def this(up:Frame) { super(up); }
* Used by Async Frame and Finish Frame
* @param classSynth
* @param conSynth
* @return a constructor block synth to add more stmts
*/
public ConstructorSynth genClassConstructorType1Base(ClassSynth classSynth){
ConstructorSynth conSynth = createConstructorSynth(classSynth);
Expr upRef = conSynth.addFormal(compilerPos, Flags.FINAL, ts.Frame(), UP.toString()); //up:Frame!
CodeBlockSynth codeBlockSynth = conSynth.createConstructorBody(compilerPos);
SuperCallSynth superCallSynth = codeBlockSynth.createSuperCall(compilerPos, classSynth.getClassDef());
superCallSynth.addArgument(ts.Frame(), upRef);
return conSynth;
}
/**
* Generate @Header def this(up:Frame, ff:FinishFrame) { super(up, ff); }
* Used by RegularFrame & TryFrame
* @param classSynth
* @param conSynth
* @return a constructor synth to add more stmts
*/
public ConstructorSynth genClassConstructorType2Base(ClassSynth classSynth){
ConstructorSynth conSynth = createConstructorSynth(classSynth);
CodeBlockSynth codeBlockSynth = conSynth.createConstructorBody(compilerPos);
Expr upRef = conSynth.addFormal(compilerPos, Flags.FINAL, ts.Frame(), UP.toString());
Expr ffRef = conSynth.addFormal(compilerPos, Flags.FINAL, ts.FinishFrame(), FF.toString());
SuperCallSynth superCallSynth = codeBlockSynth.createSuperCall(compilerPos, classSynth.getDef());
superCallSynth.addArgument(ts.Frame(), upRef);
superCallSynth.addArgument(ts.FinishFrame(), ffRef);
return conSynth;
}
/**
* Generate @Header def this(up:Frame, rd:Reducible[T]) { super(up, rd); }
* Used by FinishFrame (FinishExpr)
* @param classSynth
* @param conSynth
* @return a constructor synth to add more stmts
*/
public ConstructorSynth genClassConstructorType3Base(ClassSynth classSynth, Type reducerBaseType){
ConstructorSynth conSynth = createConstructorSynth(classSynth);
CodeBlockSynth codeBlockSynth = conSynth.createConstructorBody(compilerPos);
Type reducerType = ts.Reducible().typeArguments(Collections.singletonList(reducerBaseType));
Expr upRef = conSynth.addFormal(compilerPos, Flags.FINAL, ts.Frame(), UP.toString());
Expr rdRef = conSynth.addFormal(compilerPos, Flags.FINAL, reducerType, RD.toString());
SuperCallSynth superCallSynth = codeBlockSynth.createSuperCall(compilerPos, classSynth.getDef());
superCallSynth.addArgument(ts.Frame(), upRef);
superCallSynth.addArgument(reducerType, rdRef);
return conSynth;
}
public Name createFieldFromLocal(ClassSynth classSynth, LocalDecl ld){
Name fieldName = ld.name().id();
FieldSynth localFieldSynth = classSynth.createField(ld.position(), fieldName.toString(), ld.type().type());
localFieldSynth.addAnnotation(genUninitializedAnnotation());
localFieldSynth.addAnnotation(genSuppressTransientErrorAnnotation());
localFieldSynth.setFlags(Flags.TRANSIENT);
return fieldName;
}
public Name createReturnFlagField(ClassSynth classSynth){
FieldSynth returnFlagSynth = classSynth.createField(compilerPos, RETURN_FLAG.toString(), ts.Boolean());
returnFlagSynth.addAnnotation(genUninitializedAnnotation());
return RETURN_FLAG;
}
public Name createReturnValueField(ClassSynth classSynth, Type returnType){
FieldSynth resurnFieldSynth = classSynth.createField(compilerPos, RETURN_VALUE.toString(), returnType);
resurnFieldSynth.addAnnotation(genUninitializedAnnotation());
return RETURN_VALUE;
}
/**
* Create "@Uninitialized var pc:Int;"
*/
protected void createPCField(ClassSynth classSynth){
FieldSynth pcFieldSynth = classSynth.createField(compilerPos, PC.toString(), ts.Int());
pcFieldSynth.addAnnotation(genUninitializedAnnotation());
}
/*
* Generate cast[type1, type2](expr)
* @param type1
* @param type2
* @param expr
* @return cast[type1, type2](expr)
* @throws SemanticException
*/
Expr genCastCall(Type type1, Type type2, Expr expr, Context ct) throws SemanticException{
List<TypeNode> genericTN = new ArrayList<TypeNode>();
genericTN.add(nf.CanonicalTypeNode(compilerPos, Types.ref(type1)));
genericTN.add(nf.CanonicalTypeNode(compilerPos, Types.ref(type2)));
Call aCall = synth.makeStaticCall(compilerPos,
ts.Frame(),
Name.make("cast"),
genericTN, // This is for generic type, if any
Collections.singletonList(expr),
PlaceChecker.AddIsHereClause(type2, ct),
Collections.singletonList(type1),
ct);
return aCall;
}
/**
* Generate upcast[type1, type2](expr)
* @param type1
* @param type2
* @param expr
* @return upcast[type1, type2](expr)
* @throws SemanticException
*/
Expr genUpcastCall(Type type1, Type type2, Expr expr)throws SemanticException{
return expr;
}
/**
* Return statement throw new RuntimeException(msg + appendInfo);
* @param msg
* @param appendInfo
* @return
* @throws SemanticException
*/
protected Stmt genThrowRuntimeExceptionStmt(String msg, Expr appendInfo, Context ct) throws SemanticException {
NewInstanceSynth nis = new NewInstanceSynth(nf, ct, compilerPos, (ClassType) ts.Exception());
Expr msgRef = synth.stringValueExpr(msg, compilerPos);
Expr exceptionMsgRef = nf.Binary(compilerPos, msgRef, Binary.ADD, appendInfo).type(ts.String());
nis.addArgument(ts.String(), exceptionMsgRef);
return nf.Throw(compilerPos, nis.genExpr());
}
/**
* Transform the original main method into a new main method
* The new main method create the ws method instance, and call fast
* @param classSynth the
* @param mainMethodDecl
* @return
* @throws SemanticException
*/
public MethodDecl genNewMainMethod(ClassSynth classSynth, MethodDecl mainMethodDecl) throws SemanticException{
Context ct = classSynth.getContext();
NewInstanceSynth rSynth = new NewInstanceSynth(nf, ct, compilerPos, ts.RootFinish());
NewLocalVarSynth nvSynth = new NewLocalVarSynth(nf, ct, compilerPos, ROOT_FINISH, Flags.FINAL,
rSynth.genExpr(), ts.RootFinish(), Collections.EMPTY_LIST);
//new _main(args)
NewInstanceSynth niSynth = new NewInstanceSynth(nf, ct, compilerPos, classSynth.getClassDef().asType());
niSynth.addAnnotation(genStackAllocateAnnotation());
niSynth.addArgument(ts.Frame(), nvSynth.getLocal());
niSynth.addArgument(ts.FinishFrame(), nvSynth.getLocal());
for(Formal f : mainMethodDecl.formals()){
//now add the type
Type fType = f.localDef().type().get();
Expr formalRef = nf.Local(compilerPos, nf.Id(compilerPos, f.name().id())).localInstance(f.localDef().asInstance()).type(fType);
niSynth.addArgument(fType, formalRef);
}
Expr newMainExpr = niSynth.genExpr();
// new _main(args).run();
NewLocalVarSynth localSynth = new NewLocalVarSynth(nf, ct, compilerPos, Flags.FINAL, newMainExpr);
localSynth.addAnnotation(genStackAllocateAnnotation());
Expr mainCall = synth.makeStaticCall(compilerPos, ts.Worker(), Name.make("main"), Collections.<Expr>singletonList(localSynth.getLocal()), ts.Void(), ct);
CodeBlockSynth cbSynth = new CodeBlockSynth(nf, ct, compilerPos);
cbSynth.addStmt(nvSynth.genStmt());
cbSynth.addStmt(localSynth.genStmt());
cbSynth.addStmt(nf.Eval(compilerPos, mainCall));
return (MethodDecl) mainMethodDecl.body(cbSynth.close());
}
/**
* Generate one wrapper method
* static def fib_fast(worker:Worker!, up:Frame!, ff:FinishFrame!, pc:Int, n:Int):Int {
* @StackAllocate val _tmp = @StackAllocate new _fib(up, ff, pc, n);
* return _tmp.fast(worker);
* }
* @param containerClassDef the method's container class's def
* @param methodName the newly method's name
* @param targetClassDef the target class's def
* @param targetMethodName the target method's name, fast or slow
* @return the method synthesizer
* @throws SemanticException
*/
public X10MethodDecl genWSMethod(ClassSynth classSynth, X10MethodDecl methodDecl) throws SemanticException{
X10MethodDef methodDef =methodDecl.methodDef();
Context ct = classSynth.getContext();
X10ClassType containerClassType = (X10ClassType) methodDef.container().get();
X10ClassDef containerClassDef = containerClassType.x10Def();
String fastPathName = WSUtil.getMethodFastPathName(methodDef);
MethodSynth methodSynth;
methodSynth = new MethodSynth(nf, ct, methodDef.position(), containerClassDef, fastPathName);
methodSynth.setFlag(methodDef.flags());
methodSynth.setReturnType(methodDef.returnType().get());
String targetMethodName = FAST.toString();
//now process the formals
Expr workerRef = methodSynth.addFormal(compilerPos, Flags.FINAL, ts.Worker(), WORKER.toString());
Expr upRef = methodSynth.addFormal(compilerPos, Flags.FINAL, ts.Frame(), UP.toString());
Expr ffRef = methodSynth.addFormal(compilerPos, Flags.FINAL, ts.FinishFrame(), FF.toString());
//all other formals
List<Expr> orgFormalRefs = new ArrayList<Expr>();
List<Type> orgFormalTypes = new ArrayList<Type>();
for(Formal f : methodDecl.formals()){
orgFormalTypes.add(f.type().type());
orgFormalRefs.add(methodSynth.addFormal(f)); //all formals are added in
}
//add all type parameters (template)
X10MethodDecl mDecl = (X10MethodDecl)methodDecl;
X10MethodDef mDef = mDecl.methodDef();
int paramSize = mDef.typeParameters().size();
for(int i = 0; i < paramSize; i++){
methodSynth.addTypeParameter(mDef.typeParameters().get(i),
mDecl.typeParameters().get(i).variance());
}
//now create the body
CodeBlockSynth mBodySynth = methodSynth.getMethodBodySynth(compilerPos);
NewInstanceSynth niSynth = new NewInstanceSynth(nf, ct, classSynth.pos(), classSynth.getClassDef().asType());
niSynth.addArgument(ts.Frame(), upRef);
niSynth.addArgument(ts.FinishFrame(), ffRef);
niSynth.addArguments(orgFormalTypes, orgFormalRefs);
niSynth.addAnnotation(genStackAllocateAnnotation());
//special process for the new statement
New newE = (New) niSynth.genExpr();
Special s = (Special) newE.qualifier();
if(s != null){
s = s.qualifier(null); //clear the type node
newE = newE.qualifier(s); //this method is outer, no need qualifier typenode
}
//special process for the new statement end
NewLocalVarSynth localSynth = mBodySynth.createLocalVar(compilerPos, Flags.FINAL, newE);
localSynth.addAnnotation(genStackAllocateAnnotation());
Expr localRef = localSynth.getLocal(); //point to this inner class instance
//_tmp.fast(worker) or _temp.slow(worker)
InstanceCallSynth callSynth = new InstanceCallSynth(nf, ct, localRef, FAST.toString());
callSynth.addArgument(ts.Worker(), workerRef);
Expr callExpr = callSynth.genExpr();
//if the method has return type, insert return, others, just call them
if(callExpr.type() != null && callExpr.type() != ts.Void()){
mBodySynth.addStmt(nf.Return(compilerPos, callExpr));
}
else{
mBodySynth.addStmt(nf.Eval(callExpr.position(), callExpr));
}
return methodSynth.close();
}
public Expr genFFRef(ClassSynth classSynth) throws SemanticException {
Type cType = classSynth.getDef().asType();
Context ct = classSynth.getContext();
Expr ffRef;
if(ts.isSubtype(cType, ts.FinishFrame())){
//if it self is ff type, upcast it self
ffRef = genUpcastCall(cType, ts.FinishFrame(), genThisRef(classSynth));
}
else if(ts.isSubtype(cType, ts.AsyncFrame())){
//if it self is ff type, upcast it self
Expr upRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), UP, ct);
ffRef = genCastCall(ts.Frame(), ts.FinishFrame(), upRef, ct);
}
else{
//non finish frame will have ff field as ff
ffRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), FF, ct);
}
return ffRef;
}
/**
* Gen (Frame.cast[XXXFrameType, CollectingFinish[int]](ffRef)).accept(this.t2, worker);
* @param classSynth
* @param methodSynth
* @param offerExpr
* @param reducerType e.g. int
* @return
* @throws SemanticException
*/
public Stmt genOfferCallStmt(ClassSynth classSynth, MethodSynth methodSynth, Expr offerExpr, Type reducerType)throws SemanticException{
X10ClassType cfType = ts.CollectingFinish();
cfType = cfType.typeArguments(Collections.singletonList(reducerType));
Type cType = classSynth.getDef().asType();
Context ct = classSynth.getContext();
Expr ffRef;
Type ffRefType;
if(ts.isSubtype(cType, ts.FinishFrame())){
//if it self is ff type, upcast it self
ffRef = genThisRef(classSynth);
ffRefType = ts.FinishFrame();
}
else if(ts.isSubtype(cType, ts.AsyncFrame())){
//if it self is ff type, upcast it self
ffRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), UP, ct);
ffRefType = ts.Frame();
}
else{
//non finish frame will have ff field as ff
ffRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), FF, ct);
ffRefType = ts.Frame();
}
Expr cfRef = genCastCall(ffRefType, cfType, ffRef, ct);
Expr workerRef = methodSynth.getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
InstanceCallSynth callSynth = new InstanceCallSynth(nf, ct, cfRef, ACCEPT.toString());
callSynth.addArgument(reducerType, offerExpr);
callSynth.addArgument(ts.Worker(), workerRef);
return callSynth.genStmt();
}
/**
* Transform org call to ws call, which means call the wrapper, and add ff/parent refs.
* @param orgCall
* @param classSynth
* @param methodSynth
* @return
* @throws SemanticException
*/
public Stmt genWSCallStmt(Call orgCall, ClassSynth classSynth, MethodSynth methodSynth) throws SemanticException{
Context ct = classSynth.getContext();
MethodInstance mi = WSUtil.createWSMethodInstance(orgCall.methodInstance(), ts);
//preparing the references for invocation the call
Type cType = classSynth.getDef().asType();
Expr parentRef = genUpcastCall(cType, ts.Frame(), genThisRef(classSynth));
Expr ffRef;
if(ts.isSubtype(cType, ts.FinishFrame())){
//if it self is ff type, upcast it self
ffRef = genUpcastCall(cType, ts.FinishFrame(), genThisRef(classSynth));
}
else if(ts.isSubtype(cType, ts.AsyncFrame())){
//if it self is ff type, upcast it self
Expr upRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), UP, ct);
ffRef = genCastCall(ts.Frame(), ts.FinishFrame(), upRef, ct);
}
else{
//non finish frame will have ff field as ff
ffRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), FF, ct);
}
ArrayList<Expr> newArgs = new ArrayList<Expr>();
Expr fastWorkerRef = methodSynth.getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
newArgs.add(fastWorkerRef);
newArgs.add(parentRef);
newArgs.add(ffRef);
X10Call fastMCall = WSUtil.replaceMethodCallWithWSMethodCall(nf,(X10Call) orgCall, mi, newArgs);
return nf.Eval(orgCall.position(), fastMCall);
}
/**
* Used by back method to generate aVar = cast[Frame,()=>xType](frame)();
* @param methodSynth
* @param type
* @param assign
* @return
* @throws SemanticException
*/
public Stmt genBackAssignStmt(MethodSynth methodSynth, Type type, Assign assign) throws SemanticException{
// _m_fib.t1 = cast[Frame,()=>Int](frame)();
Context ct = methodSynth.getContext();
Expr backFrameRef = methodSynth.getMethodBodySynth(compilerPos).getLocal(FRAME.toString());
Expr castExp = genCastCall(ts.Frame(),
synth.simpleFunctionType(type, compilerPos),
backFrameRef, ct);
//FIXME: it should be a closure call. However, an instance call here is simpler.
InstanceCallSynth niSynth = new InstanceCallSynth(nf, ct, compilerPos, castExp, OPERATOR.toString());
assign = assign.right(niSynth.genExpr());
return nf.Eval(assign.position(), assign);
}
/**
* Generate invocation stmts to sub frames
* @param pc the target pc after the call
* @param classSynth the current class's synth
* @param newClassGen
* @return
* @throws SemanticException
*/
public List<Stmt> genInvocateFrameStmts(int pc, ClassSynth classSynth, MethodSynth methodSynth, AbstractWSClassGen newClassGen) throws SemanticException{
List<Stmt> stmts = new ArrayList<Stmt>();
ClassType classType = classSynth.getClassDef().asType();
ClassType newClassType = newClassGen.getClassType();
Context ct = classSynth.getContext();
//pc = x;
try{
//check whether the frame contains pc field. For optimized finish frame and async frame, there is no pc field
stmts.add(genPCAssign(classSynth, pc));
}
catch(polyglot.types.NoMemberException e){
//Just ignore the pc assign statement
}
Expr workerRef = methodSynth.getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
//if the new frame is an async frame, push() instructions should be inserted here
if(ts.isSubtype(newClassType, ts.AsyncFrame())){
stmts.add(genContinuationPush(classSynth, workerRef));
}
//create the instance
NewInstanceSynth niSynth = new NewInstanceSynth(nf, ct, compilerPos, newClassType);
//first parameter in constructor, parent
if(ts.isSubtype(newClassType, ts.AsyncFrame())){
Expr ffRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), FF, ct);
Expr parentRef = genUpcastCall(ts.FinishFrame(), ts.Frame(), ffRef);
niSynth.addArgument(ts.Frame(), parentRef);
}
else{ //upcast[_selfType,Frame](this);
Expr parentRef = genUpcastCall(classType, ts.Frame(), genThisRef(classSynth));
niSynth.addArgument(ts.Frame(), parentRef);
}
//process the 2nd parameter, ff.
if(!ts.isSubtype(newClassType, ts.FinishFrame()) && !ts.isSubtype(newClassType, ts.AsyncFrame())){
//if target is not finish frame, need add ff as reference
Expr ffRef;
if(ts.isSubtype(classType, ts.FinishFrame())){
//if itself is ff type, upcast it self
ffRef = genUpcastCall(classType, ts.FinishFrame(), genThisRef(classSynth));
}
else if(ts.isSubtype(classType, ts.AsyncFrame())){
//if itself is async type, upcast it's up field
Expr upRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), UP, ct);
ffRef = genCastCall(ts.Frame(), ts.FinishFrame(), upRef, ct);
} else {
//non finish frame will have ff field as ff
ffRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), FF, ct);
}
niSynth.addArgument(ts.FinishFrame(), ffRef);
}
//Finally, if the newClassType is an async frame, may consider the adding formal
if(ts.isSubtype(newClassType, ts.AsyncFrame())){
WSAsyncClassGen asyncGen = (WSAsyncClassGen)newClassGen;
//need access each formal, and add them into the parameters
for(Pair<Name, Type> formal : asyncGen.formals){
//make an access to the value; The value is referenced from async's parent continuation frame
Expr fieldContainerRef = asyncGen.parentK.getFieldContainerRef(formal.fst(), formal.snd());
Expr fieldRef = synth.makeFieldAccess(compilerPos, fieldContainerRef, formal.fst(), ct).type(formal.snd());
niSynth.addArgument(formal.snd(), fieldRef);
}
}
niSynth.addAnnotation(genStackAllocateAnnotation());
NewLocalVarSynth localSynth = new NewLocalVarSynth(nf, ct, compilerPos, Flags.FINAL, niSynth.genExpr());
localSynth.addAnnotation(genStackAllocateAnnotation());
stmts.add(localSynth.genStmt());
//now the instance's fast/slow method call
Expr localRef = localSynth.getLocal(); // point to this inner class's instance
InstanceCallSynth callSynth = new InstanceCallSynth(nf, ct, compilerPos, localRef, FAST.toString());
callSynth.addArgument(ts.Worker(), workerRef);
stmts.add(callSynth.genStmt());
return stmts;
}
/*
* Used by TryStmt transformation
* worker.rethrow();
*/
protected Stmt genRethrowStmt(MethodSynth methodSynth) throws SemanticException{
Context ct = methodSynth.getContext();
Expr workerRef = methodSynth.getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
InstanceCallSynth icSynth = new InstanceCallSynth(nf, ct, compilerPos, workerRef, RETHROW.toString());
return icSynth.genStmt();
}
/**
* Generate an annotation node of type annotationType
* WS will use the following types: Inline, StackAllocate, Uninitialized, Header
*
* @param annotationType
* @return
*/
AnnotationNode genAnnotationNode(Type annotationType){
TypeNode annoTN = nf.CanonicalTypeNode(compilerPos, annotationType).typeRef(Types.ref(annotationType));
return nf.AnnotationNode(compilerPos, annoTN);
}
AnnotationNode genStackAllocateAnnotation(){
return genAnnotationNode(ts.StackAllocate());
}
AnnotationNode genHeaderAnnotation(){
return genAnnotationNode(ts.Header());
}
AnnotationNode genInlineAnnotation(){
return genAnnotationNode(ts.InlineOnly());
}
AnnotationNode genUninitializedAnnotation(){
return genAnnotationNode(ts.Uninitialized());
}
AnnotationNode genSuppressTransientErrorAnnotation(){
return genAnnotationNode(ts.SuppressTransientError());
}
public Stmt genPCAssign(ClassSynth classSynth, int pc) throws SemanticException{
Context ct = classSynth.getContext();
Expr pcAssgn = synth.makeFieldAssign(compilerPos, genThisRef(classSynth), PC,
synth.intValueExpr(pc, compilerPos), ct).type(ts.Int());
return nf.Eval(compilerPos, pcAssgn);
}
/**
* Generate val rRootFinish:RemoteRootFinish = new RemoteRootFinish(ff);
* @param classSynth
* @return
* @throws SemanticException
*/
public Pair<Stmt, Expr> genRemoteRootFinishInitializer(ClassSynth classSynth) throws SemanticException{
Expr ffRef = genFFFieldRef(classSynth);
Context ct = classSynth.getContext();
//prepare val rRootFinish:RemoteRootFinish = new RemoteRootFinish(ff).init();
NewInstanceSynth remoteRootFFSynth = new NewInstanceSynth(nf, ct, compilerPos, ts.RemoteFinish());
remoteRootFFSynth.addAnnotation(genStackAllocateAnnotation());
remoteRootFFSynth.addArgument(ts.FinishFrame(), ffRef);
NewLocalVarSynth remoteRootFFRefLocalSynth = new NewLocalVarSynth(nf, ct, compilerPos, Flags.FINAL, remoteRootFFSynth.genExpr());
remoteRootFFRefLocalSynth.addAnnotation(genStackAllocateAnnotation());
Expr remoteRootFFRef = remoteRootFFRefLocalSynth.getLocal();
return new Pair<Stmt, Expr>(remoteRootFFRefLocalSynth.genStmt(), remoteRootFFRef);
}
public Stmt genRunAsyncAt(ClassSynth classSynth, Expr place, Type remoteMainFrameType, Expr remoteMainRef) throws SemanticException{
Context ct = classSynth.getContext();
if (ts.hasSameClassDef(Types.baseType(place.type()), ts.GlobalRef())) {
place = synth.makeFieldAccess(compilerPos ,place, ts.homeName(), ct);
}
InstanceCallSynth callSynth = new InstanceCallSynth(nf, ct, compilerPos, nf.CanonicalTypeNode(compilerPos, ts.Worker()), RUN_ASYNC_AT.toString());
callSynth.addArgument(ts.Place(), place);
callSynth.addArgument(remoteMainFrameType, remoteMainRef);
return callSynth.genStmt();
}
public Stmt genRunAt(ClassSynth classSynth, Expr place, Type remoteMainFrameType, Expr remoteMainRef) throws SemanticException{
Context ct = classSynth.getContext();
if (ts.hasSameClassDef(Types.baseType(place.type()), ts.GlobalRef())) {
place = synth.makeFieldAccess(compilerPos ,place, ts.homeName(), ct);
}
InstanceCallSynth callSynth = new InstanceCallSynth(nf, ct, compilerPos, nf.CanonicalTypeNode(compilerPos, ts.Worker()), RUN_AT.toString());
callSynth.addArgument(ts.Place(), place);
callSynth.addArgument(remoteMainFrameType, remoteMainRef);
return callSynth.genStmt();
}
/**
* Generate upcast[_finish_body,Continuation](this).push(worker);
* The worker ref is different for fast/resume path
* @param workerRef
* @return
* @throws SemanticException
*/
protected Stmt genContinuationPush(ClassSynth classSynth, Expr workerRef) throws SemanticException{
Type classType = classSynth.getClassDef().asType();
Context ct = classSynth.getContext();
// push(worker)
Expr castThisRef = genUpcastCall(classType, ts.RegularFrame(), genThisRef(classSynth));
InstanceCallSynth icSynth = new InstanceCallSynth(nf, ct, compilerPos, castThisRef, PUSH.toString());
// continuationFrame
icSynth.addArgument(ts.Worker(), workerRef);
return icSynth.genStmt();
}
public Expr genThisRef(ClassSynth classSynth){
Type type = classSynth.getClassDef().asType();
return synth.thisRef(type, compilerPos);
}
public Expr genFFFieldRef(ClassSynth classSynth) throws SemanticException{
return synth.makeFieldAccess(compilerPos, genThisRef(classSynth), FF, classSynth.getContext());
}
public Expr genPCRef(ClassSynth classSynth) throws SemanticException{
Context ct = classSynth.getContext();
Expr pcRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), PC, ct);
return pcRef;
}
/**
* Generate
* try { tryBodyStmts}
* catch (t:x10.compiler.Abort) { throw t; }
* catch (t:x10.lang.Throwable) { this.caught(t); }
* Used by Async frame and finish frame. The catch Abort will not be generated here.
* It will be added in later compilation pass
* @param tryBodyStmts
* @return
* @throws SemanticException
*/
public Try genExceptionHandler(List<Stmt> tryBodyStmts, ClassSynth classSynth) throws SemanticException {
Context ct = classSynth.getContext();
Name formalName = ct.getNewVarName();
Formal f = synth.createFormal(compilerPos, ts.Exception(), formalName, Flags.NONE);
Expr caught = synth.makeInstanceCall(compilerPos, genThisRef(classSynth),
CAUGHT, Collections.<TypeNode>emptyList(), Collections.<Expr>singletonList(
nf.Local(compilerPos, nf.Id(compilerPos, formalName)).localInstance(f.localDef().asInstance()).type(ts.Exception())), ts.Void(),
Collections.<Type>singletonList(ts.Exception()), ct);
Catch c = nf.Catch(compilerPos, f, nf.Block(compilerPos,
nf.Eval(compilerPos, caught)));
Try t = nf.Try(compilerPos, nf.Block(compilerPos, tryBodyStmts), Collections.<Catch>singletonList(c));
return t;
}
/**
* Used by Finish frame's rethrow
* @param classSynth
* @return
* @throws SemanticException
*/
public Stmt genRethrowStmt(ClassSynth classSynth) throws SemanticException{
//fast path: //upcast[_async,AsyncFrame](this).rethrow(worker);
Context ct = classSynth.getContext();
InstanceCallSynth icSynth = new InstanceCallSynth(nf, ct, compilerPos, genThisRef(classSynth), RETHROW.toString());
return icSynth.genStmt();
}
public Stmt genReturnResultStmt(ClassSynth classSynth) throws SemanticException{
Context ct = classSynth.getContext();
Expr resultRef = synth.makeFieldAccess(compilerPos, genThisRef(classSynth), RETURN_VALUE, ct);
return nf.Return(compilerPos, resultRef);
}
/**
* Generate this.continueLater(worker); Used by blocking constructs, such as when
* @param classSynth
* @param methodSynth
* @return
* @throws SemanticException
*/
public Stmt genContinueLaterStmt(ClassSynth classSynth, MethodSynth methodSynth) throws SemanticException{
Type ctype = classSynth.getClassDef().asType();
Context ct = classSynth.getContext();
Expr thisRef = genUpcastCall(ctype, ts.RegularFrame(), genThisRef(classSynth));
InstanceCallSynth redoCallSynth = new InstanceCallSynth(nf, ct, compilerPos, thisRef, CONTINUE_LATER.toString());
Expr workerRef = methodSynth.getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
redoCallSynth.addArgument(ts.Worker(), workerRef);
return redoCallSynth.genStmt();
}
/**
* Generate this.continueNow(worker); Used to move frames to heap in remote frame transform
* @param classSynth
* @param methodSynth
* @return
* @throws SemanticException
*/
public Stmt genContinueNowStmt(ClassSynth classSynth, MethodSynth methodSynth) throws SemanticException{
Type ctype = classSynth.getClassDef().asType();
Context ct = classSynth.getContext();
Expr thisRef = genUpcastCall(ctype, ts.RegularFrame(), genThisRef(classSynth));
InstanceCallSynth redoCallSynth = new InstanceCallSynth(nf, ct, compilerPos, thisRef, CONTINUE_NOW.toString());
Expr workerRef = methodSynth.getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
redoCallSynth.addArgument(ts.Worker(), workerRef);
return redoCallSynth.genStmt();
}
/**
* Used by async frame, gen "this.poll(worker)"
* @param classSynth
* @param methodSynth
* @return
* @throws SemanticException
*/
public Stmt genPollStmt(ClassSynth classSynth, MethodSynth methodSynth) throws SemanticException{
//fast path: //upcast[_async,AsyncFrame](this).poll(worker);
Type cType = classSynth.getClassDef().asType();
Context ct = classSynth.getContext();
Expr upThisExpr = genUpcastCall(cType, ts.AsyncFrame(), genThisRef(classSynth));
InstanceCallSynth icSynth = new InstanceCallSynth(nf, ct, compilerPos, upThisExpr, POLL.toString());
Expr fastWorkerRef = methodSynth.getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
icSynth.addArgument(ts.Worker(), fastWorkerRef);
return icSynth.genStmt();
}
// public Expr getFastWorkerRef() {
// return classFrame.getFastMethodSynth().getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
// }
//
// public Expr getResumeWorkerRef() {
// return classFrame.getResumeMethodSynth().getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
// }
//
// public Expr getBackWorkerRef() {
// return classFrame.getBackMethodSynth().getMethodBodySynth(compilerPos).getLocal(WORKER.toString());
// }
// public Expr getBackFrameRef() {
// return classFrame.getResumeMethodSynth().getMethodBodySynth(compilerPos).getLocal(FRAME.toString());
// }
}