/* * 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 java.util.Set; import polyglot.ast.Assign; import polyglot.ast.Binary; import polyglot.ast.Block; import polyglot.ast.Call; import polyglot.ast.Eval; import polyglot.ast.Expr; import polyglot.ast.For; import polyglot.ast.ForInit; import polyglot.ast.If; import polyglot.ast.LocalDecl; import polyglot.ast.Loop; import polyglot.ast.Node; import polyglot.ast.NodeFactory; import polyglot.ast.Stmt; import polyglot.ast.Switch; import polyglot.ast.Try; import polyglot.frontend.Job; import polyglot.types.ClassDef; import polyglot.types.ClassType; import polyglot.types.Context; import polyglot.types.Flags; import polyglot.types.Name; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.Types; import polyglot.util.Pair; import x10.ast.Async; import x10.ast.AtStmt; import x10.ast.Finish; import x10.ast.FinishExpr; import x10.ast.ForLoop; import x10.ast.Offer; import x10.ast.StmtSeq; import x10.ast.When; import x10.ast.X10Loop; import x10.compiler.ws.WSTransformState; import x10.compiler.ws.util.AddIndirectLocalDeclareVisitor; import x10.compiler.ws.util.ClosureDefReinstantiator; import x10.compiler.ws.util.CodePatternDetector; import x10.compiler.ws.util.TransCodes; import x10.compiler.ws.util.Triple; import x10.compiler.ws.util.WSUtil; import x10.optimizations.ForLoopOptimizer; import x10.types.X10ClassDef; import x10.util.CollectionFactory; import x10.util.synthesizer.CodeBlockSynth; import x10.util.synthesizer.InstanceCallSynth; import x10.util.synthesizer.NewInstanceSynth; import x10.util.synthesizer.NewLocalVarSynth; import x10.util.synthesizer.SuperCallSynth; import x10.util.synthesizer.SwitchSynth; /** * @author Haichuan * * Used to generate a normal code block's fast/slow/back It can process finish * statement as well as simple method invocation. Finish -> translate to finish * stmt class Method invoke -> if the target method is a parallel method, * translate to fast/slow/back call * * The inner class extends RegularFrame * */ public class WSRegularFrameClassGen extends AbstractWSClassGen { //this flag is set to true when genReturnCheckStmt() is called. //And set to false every time a new statement is processed. //In this cause, the original full coverage return was limited. //And If there is on any additional statements after the returnCheckPath, //we need add an additional return to prevent the java path has no "return x" at the end of the method boolean isReturnPathChanged; // method frames protected WSRegularFrameClassGen(Job job, NodeFactory xnf, Context xct, WSTransformState wts, String className, Stmt stmt, X10ClassDef outer, Flags flags, ClassType superType) { super(job, xnf, xct, wts, className, superType, flags, outer, WSUtil.setSpeicalQualifier(stmt, outer, xnf)); wsynth.createPCField(classSynth); } // nested frames protected WSRegularFrameClassGen(AbstractWSClassGen parent, Stmt stmt, String classNamePrefix) { super(parent, parent, classNamePrefix, parent.xts.RegularFrame(), stmt); wsynth.createPCField(classSynth); } // remote frames: at(p) & async at(p) protected WSRegularFrameClassGen(AbstractWSClassGen parent, AbstractWSClassGen up, Stmt stmt, String classNamePrefix, ClassType frameType) { super(parent, up, classNamePrefix, frameType, stmt); wsynth.createPCField(classSynth); } @Override protected void genMethods() throws SemanticException { if (codeBlock == null) { fastMSynth.setFlag(Flags.ABSTRACT); resumeMSynth.setFlag(Flags.ABSTRACT); backMSynth.setFlag(Flags.ABSTRACT); classSynth.setFlags(Flags.ABSTRACT); return; } Triple<CodeBlockSynth, SwitchSynth, SwitchSynth> bodyCodes = transformMethodBody(); CodeBlockSynth fastBodySynth = bodyCodes.first(); fastMSynth.setMethodBodySynth(fastBodySynth); CodeBlockSynth resumeBodySynth = resumeMSynth.getMethodBodySynth(compilerPos); resumeBodySynth.addStmt(bodyCodes.second().genStmt()); CodeBlockSynth backBodySynth = backMSynth.getMethodBodySynth(compilerPos); backBodySynth.addStmt(bodyCodes.third().genStmt()); } protected Triple<CodeBlockSynth, SwitchSynth, SwitchSynth> transformMethodBody() throws SemanticException { CodeBlockSynth fastBodySynth = new CodeBlockSynth(xnf, xct, compilerPos); Expr pcRef = wsynth.genPCRef(classSynth); SwitchSynth resumeSwitchSynth = new SwitchSynth(xnf, xct, compilerPos, pcRef); SwitchSynth backSwitchSynth = new SwitchSynth(xnf, xct, compilerPos, pcRef); ArrayList<Stmt> bodyStmts = new ArrayList<Stmt>(codeBlock.statements()); int pcValue = 0; // The current pc value. Will increase every time an // inner class is created int prePcValue = 0; // The current pc value. Will increase every time an // inner class is created boolean isInResumePath = false; //For both c++ & java path, "at" & "async at" should be executed in resume path Set<Name> localDeclaredVar = CollectionFactory.newHashSet(); //all locals with these names will not be replaced while (bodyStmts.size() > 0) { Stmt s = bodyStmts.remove(0); //always remove the first one isReturnPathChanged = false; //have one statement, and should have return path TransCodes codes; //the main codes // need process local declare first if (s instanceof LocalDecl) { // Pre-processing s = transLocalDecl((LocalDecl) s); if(s == null) continue; if (s instanceof LocalDecl){ //this local is not transformed as a field. Record it localDeclaredVar.add(((LocalDecl) s).name().id()); } } // need analyze out-finish scope local assign if(s instanceof Eval){ localAssignEscapeProcess((Eval)s); } //use code pattern detector to detect CodePatternDetector.Pattern pattern = CodePatternDetector.detectAndTransform(s, wts); switch(pattern){ case Simple: codes = transNormalStmt(s, prePcValue, localDeclaredVar); break; case StmtSeq: //Unwrapp the stmts, and add them back bodyStmts.addAll(0, WSUtil.unwrapToStmtList(s)); //put them into target continue; case Finish: codes = transFinish((Finish)s, prePcValue); break; case Async: codes = transAsync((Async)s, prePcValue); break; case At: if(!isInResumePath){ codes = genSwitchToResumePathCodes(prePcValue); isInResumePath = true; bodyStmts.add(0, s); //transform the statement next loop } else{ codes = transAtAsyncAt((AtStmt)s, prePcValue, false, null, localDeclaredVar); } break; case AsyncAt: if(!isInResumePath){ codes = genSwitchToResumePathCodes(prePcValue); isInResumePath = true; bodyStmts.add(0, s); //transform the statement next loop } else{ Async async = (Async)s; codes = transAtAsyncAt(s, prePcValue, true, async.clocks(), localDeclaredVar); } break; case When: codes = transWhen((When)s, prePcValue); break; case Call: codes = transCall((Call)((Eval)s).expr(), prePcValue, localDeclaredVar); break; case AssignCall: codes = transAssignCall(((Eval)s), prePcValue, localDeclaredVar); break; case If: codes = transIf((If) s, prePcValue); break; case For: codes = transFor((For) s, prePcValue); break; case While: case DoWhile: codes = transWhileDoLoop((Loop) s, prePcValue); break; case Switch: codes = transSwitch((Switch) s, prePcValue); break; case Block: codes = transBlock((Block) s, prePcValue, WSUtil .getBlockFrameClassName(className)); break; case Try: codes = transTry((Try) s, prePcValue); break; case FinishExprAssign: codes = transFinishExprAssign((Eval)s, prePcValue, localDeclaredVar); break; case Unsupport: default: WSUtil.err("X10 WorkStealing cannot support:", s); continue; } pcValue = codes.pcValue(); fastBodySynth.addStmts(codes.getFastStmts()); resumeSwitchSynth.insertStatementsInCondition(prePcValue, codes.getResumeStmts()); if(codes.getResumePostStmts().size() > 0){ resumeSwitchSynth.insertStatementsInCondition(pcValue, codes.getResumePostStmts()); } if(codes.getBackStmts().size() > 0){ //only assign call has back backSwitchSynth.insertStatementsInCondition(pcValue, codes.getBackStmts()); backSwitchSynth.insertStatementInCondition(pcValue, xnf.Break(compilerPos)); } prePcValue = pcValue; } // for loop end //processing the return if the return was impacted by return check stmt; //should only be executed in method frame if(isReturnPathChanged){ Type returnType = fastMSynth.getDef().returnType().get(); if(returnType != null && returnType != xts.Void()){ //add return statement although it should not be exectued fastBodySynth.addStmt(wsynth.genReturnResultStmt(classSynth)); } } return new Triple<CodeBlockSynth, SwitchSynth, SwitchSynth>(fastBodySynth, resumeSwitchSynth, backSwitchSynth); } /** * At least one path is complex path. But condition is not (otherwise it is a compound stmt) */ protected TransCodes transIf(If ifS, int prePcValue) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); // condition need replace ifS = ifS.cond((Expr) this.replaceLocalVarRefWithFieldAccess(ifS.cond())); If fastIf, slowIf; //two path; // true condition block Stmt conS = ifS.consequent(); if (WSUtil.isComplexCodeNode(conS, wts)) { Block ifConBlock = (conS instanceof Block) ? (Block) conS : synth.toBlock(conS); TransCodes conCodes = transBlock(ifConBlock, prePcValue, WSUtil.getIFBlockClassName(className, true)); fastIf = ifS.consequent(xnf.Block(conS.position(), conCodes.getFastStmts())); //note the resume path codes has no return check slowIf = ifS.consequent(xnf.Block(conS.position(), conCodes.getResumeStmts())); } else{ //should use transNormal, not use directly replace TransCodes ifTCodes = transNormalStmt(conS, prePcValue, Collections.EMPTY_SET); fastIf = ifS.consequent(WSUtil.seqStmtsToOneStmt(xnf, ifTCodes.getFastStmts().get(0))); //note the resume path codes has no return check slowIf = ifS.consequent(WSUtil.seqStmtsToOneStmt(xnf, ifTCodes.getResumeStmts().get(0))); } Stmt altS = ifS.alternative(); if (altS != null) { if (WSUtil.isComplexCodeNode(altS, wts)) { Block ifAltBlock = (altS instanceof Block) ? (Block) altS : synth.toBlock(altS); TransCodes altCodes = transBlock(ifAltBlock, prePcValue, WSUtil.getIFBlockClassName(className, false)); fastIf = fastIf.alternative(xnf.Block(altS.position(), altCodes.getFastStmts())); slowIf = slowIf.alternative(xnf.Block(altS.position(), altCodes.getResumeStmts())); } else{ //should use transNormal, not use directly replace TransCodes ifFCodes = transNormalStmt(altS, prePcValue, Collections.EMPTY_SET); fastIf = fastIf.alternative(WSUtil.seqStmtsToOneStmt(xnf, ifFCodes.getFastStmts().get(0))); slowIf = slowIf.alternative(WSUtil.seqStmtsToOneStmt(xnf, ifFCodes.getResumeStmts().get(0))); } } transCodes.addFast(fastIf); transCodes.addResume(slowIf); transCodes.increasePC(); //Add add the return check code if(WSUtil.hasReturnStatement(ifS)){ //The code is after pc change transCodes.addFast(genReturnCheckStmt(true)); transCodes.addPostResume(genReturnCheckStmt(false)); } return transCodes; } protected TransCodes transWhileDoLoop(Loop loop, int prePcValue) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); AbstractWSClassGen loopClassGen = genChildFrame(xts.RegularFrame(), loop, null); //prepare child frame call; List<Stmt> fastStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, fastMSynth, loopClassGen); List<Stmt> resumeStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, resumeMSynth, loopClassGen); transCodes.addFast(fastStmts); transCodes.addResume(resumeStmts); transCodes.increasePC(); if(WSUtil.hasReturnStatement(loop)){ //The code is after pc change transCodes.addFast(genReturnCheckStmt(true)); transCodes.addPostResume(genReturnCheckStmt(false)); } return transCodes; } protected TransCodes transFor(For f, int prePcValue) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); AbstractWSClassGen forClassGen = genChildFrame(xts.RegularFrame(), f, null); //prepare child frame call; List<Stmt> fastStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, fastMSynth, forClassGen); List<Stmt> resumeStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, resumeMSynth, forClassGen); transCodes.addFast(fastStmts); transCodes.addResume(resumeStmts); transCodes.increasePC(); if(WSUtil.hasReturnStatement(f)){ //The code is after pc change transCodes.addFast(genReturnCheckStmt(true)); transCodes.addPostResume(genReturnCheckStmt(false)); } return transCodes; } protected TransCodes transFinish(Finish f, int prePcValue) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); AbstractWSClassGen finishClassGen = genChildFrame(xts.FinishFrame(), f, null); //prepare child frame call; List<Stmt> fastStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, fastMSynth, finishClassGen); List<Stmt> resumeStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, resumeMSynth, finishClassGen); transCodes.addFast(fastStmts); transCodes.addResume(resumeStmts); transCodes.increasePC(); return transCodes; } protected TransCodes transFinishExprAssign(Eval s, int prePcValue, Set<Name> declaredLocals) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); Assign assign = (Assign) s.expr(); FinishExpr finishExpr = (FinishExpr) assign.right(); Expr reducer = finishExpr.reducer(); Type reducerBaseType = Types.reducerType(reducer.type()); //get the base type reducer = (Expr) replaceLocalVarRefWithFieldAccess(reducer, declaredLocals); AbstractWSClassGen collectingFinishFrameGen = new WSFinishStmtClassGen(this, reducerBaseType, finishExpr); collectingFinishFrameGen.genClass(); //now start invocating the class's fast/resume/ //pc = x; try{ //check whether the frame contains pc field. For optimized finish frame and async frame, there is no pc field Stmt pcAssign = wsynth.genPCAssign(classSynth, prePcValue + 1); transCodes.addFast(pcAssign); transCodes.addResume(pcAssign); } catch(polyglot.types.NoMemberException e){ //Just ignore the pc assign statement } NewInstanceSynth niSynth = new NewInstanceSynth(xnf, xct, compilerPos, collectingFinishFrameGen.getClassType()); Expr parentRef = wsynth.genUpcastCall(getClassType(), xts.Frame(), wsynth.genThisRef(classSynth)); niSynth.addArgument(xts.Frame(), parentRef); //process the second one, reducer niSynth.addArgument(reducer.type(), reducer); niSynth.addAnnotation(wsynth.genStackAllocateAnnotation()); NewLocalVarSynth localSynth = new NewLocalVarSynth(xnf, xct, compilerPos, Flags.FINAL, niSynth.genExpr()); localSynth.addAnnotation(wsynth.genStackAllocateAnnotation()); Stmt niS = localSynth.genStmt(); transCodes.addFast(niS); transCodes.addResume(niS); //now the instance's fast/slow method call Expr localRef = localSynth.getLocal(); Expr fastWorkerRef = fastMSynth.getMethodBodySynth(compilerPos).getLocal(WSSynthesizer.WORKER.toString()); Expr resumeWorkerRef = resumeMSynth.getMethodBodySynth(compilerPos).getLocal(WSSynthesizer.WORKER.toString()); InstanceCallSynth fastPathCallSynth = new InstanceCallSynth(xnf, xct, compilerPos, localRef, WSSynthesizer.FAST.toString()); fastPathCallSynth.addArgument(xts.Worker(), fastWorkerRef); transCodes.addFast(fastPathCallSynth.genStmt()); InstanceCallSynth resumePathCallSynth = new InstanceCallSynth(xnf, xct, compilerPos, localRef, WSSynthesizer.FAST.toString()); resumePathCallSynth.addArgument(xts.Worker(), resumeWorkerRef); transCodes.addResume(resumePathCallSynth.genStmt()); //finally - the assign assign = (Assign) replaceLocalVarRefWithFieldAccess(assign, declaredLocals); //fast result assign; InstanceCallSynth fastPathResultCallSynth = new InstanceCallSynth(xnf, xct, compilerPos, localRef, WSSynthesizer.CF_RESULT_FAST.toString()); fastPathResultCallSynth.addArgument(xts.Worker(), fastWorkerRef); Stmt fastAssign = xnf.Eval(assign.position(), assign.right(fastPathResultCallSynth.genExpr())); transCodes.addFast(fastAssign); //resume InstanceCallSynth resumePathResultCallSynth = new InstanceCallSynth(xnf, xct, compilerPos, localRef, WSSynthesizer.CF_RESULT_FAST.toString()); resumePathResultCallSynth.addArgument(xts.Worker(), resumeWorkerRef); Stmt resumeAssign = xnf.Eval(assign.position(), assign.right(resumePathResultCallSynth.genExpr())); transCodes.addResume(fastAssign); //back transCodes.increasePC(); Expr backFrameRef = backMSynth.getMethodBodySynth(compilerPos).getLocal(WSSynthesizer.FRAME.toString()); Expr castExp = wsynth.genCastCall(xts.Frame(), xts.CollectingFinish().typeArguments(Collections.singletonList(reducerBaseType)), backFrameRef, xct); InstanceCallSynth backResultCallSynth = new InstanceCallSynth(xnf, xct, compilerPos, castExp, WSSynthesizer.CF_RESULT.toString()); Stmt backAssign = xnf.Eval(assign.position(), assign.right(backResultCallSynth.genExpr())); transCodes.addBack(backAssign); //and process the back return transCodes; } protected TransCodes transWhen(When w, int prePcValue) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); AbstractWSClassGen whenClassGen = genChildFrame(xts.RegularFrame(), w, null); //prepare child frame call; List<Stmt> fastStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, fastMSynth, whenClassGen); List<Stmt> resumeStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, resumeMSynth, whenClassGen); transCodes.addFast(fastStmts); transCodes.addResume(resumeStmts); transCodes.increasePC(); return transCodes; } /** * Generate switch to resume path statements. In fast path; * _pc = x; * continueNow(worker) * @param prePcValue * @return * @throws SemanticException */ protected TransCodes genSwitchToResumePathCodes(int prePcValue) throws SemanticException{ TransCodes transCodes = new TransCodes(prePcValue); //_pc = x; try{ //check whether the frame contains pc field. For optimized finish frame and async frame, there is no pc field Stmt pcAssign = wsynth.genPCAssign(classSynth, prePcValue + 1); transCodes.addFast(pcAssign); transCodes.addResume(pcAssign); } catch(polyglot.types.NoMemberException e){ //Just ignore the pc assign statement if there is no pc field in the frame } Stmt fastRedoCallStmt = wsynth.genContinueNowStmt(classSynth, fastMSynth); transCodes.addFast(fastRedoCallStmt); transCodes.increasePC(); return transCodes; } /** * @param atStmt the at stmt or the async at stmt * @param prePcValue * @param isAsync true: async at(P) S; false: at(P)S * @param clocks: only useful when isAsync == true * @return two transcodes, because the pc will change more than once * @throws SemanticException */ protected TransCodes transAtAsyncAt(Stmt stmt, int prePcValue, boolean isAsync, List<Expr> clocks, //not use clocks now Set<Name> declaredLocals) throws SemanticException{ TransCodes transCodes = new TransCodes(prePcValue); //remote call doesn't need increase pc //transformation step by step: //prepare val rRootFinish:RemoteRootFinish = new RemoteRootFinish(ff); Pair<Stmt, Expr> remoteFFPair = wsynth.genRemoteRootFinishInitializer(classSynth); transCodes.addFast(remoteFFPair.fst()); transCodes.addResume(remoteFFPair.fst()); //create the frame class gen WSRemoteMainFrameClassGen remoteClassGen = (WSRemoteMainFrameClassGen) genChildFrame(xts.RegularFrame(), stmt, null); //no need prefix gen here //FIXME: should be merged into gen class invocation stmts //Prepare the instance //val rFrame = new _mainR0(rRootFinish, rRootFinish, n1); NewInstanceSynth remoteMainSynth = new NewInstanceSynth(xnf, xct, compilerPos, remoteClassGen.getClassType()); remoteMainSynth.addAnnotation(wsynth.genStackAllocateAnnotation()); if (isAsync) { remoteMainSynth.addArgument(xts.RemoteFinish(), remoteFFPair.snd()); } else { //Create the at frame wrapper NewInstanceSynth remoteAtFrameSynth = new NewInstanceSynth(xnf, xct, compilerPos, xts.AtFrame()); remoteAtFrameSynth.addAnnotation(wsynth.genStackAllocateAnnotation()); remoteAtFrameSynth.addArgument(xts.Frame(), getThisRef()); remoteAtFrameSynth.addArgument(xts.RemoteFinish(), remoteFFPair.snd()); NewLocalVarSynth remoteAtFrameLocalSynth = new NewLocalVarSynth(xnf, xct, compilerPos, Flags.FINAL, remoteAtFrameSynth.genExpr()); remoteAtFrameLocalSynth.addAnnotation(wsynth.genStackAllocateAnnotation()); transCodes.addFast(remoteAtFrameLocalSynth.genStmt()); transCodes.addResume(remoteAtFrameLocalSynth.genStmt()); Expr remoteAtFrame = remoteAtFrameLocalSynth.getLocal(); remoteMainSynth.addArgument(xts.Frame(), remoteAtFrame); } remoteMainSynth.addArgument(xts.RemoteFinish(), remoteFFPair.snd()); //iterate add all formals required for(Pair<Name, Type> formal : remoteClassGen.formals){ //make an access to the value; Expr fieldContainerRef = this.getFieldContainerRef(formal.fst(), formal.snd()); Expr fieldRef = synth.makeFieldAccess(compilerPos, fieldContainerRef, formal.fst(), xct).type(formal.snd()); remoteMainSynth.addArgument(formal.snd(), fieldRef); } NewLocalVarSynth remoteMainLocalSynth = new NewLocalVarSynth(xnf, xct, compilerPos, Flags.FINAL, remoteMainSynth.genExpr()); remoteMainLocalSynth.addAnnotation(wsynth.genStackAllocateAnnotation()); transCodes.addFast(remoteMainLocalSynth.genStmt()); transCodes.addResume(remoteMainLocalSynth.genStmt()); Expr remoteMainRef = remoteMainLocalSynth.getLocal(); //Prepare worker call //worker.remoteRunFrame(here.next(), rFrame, ff); //need change place to place.home if place is a GlobalRef Expr place = (Expr) this.replaceLocalVarRefWithFieldAccess(remoteClassGen.getPlace(), declaredLocals); if(isAsync) { Stmt asyncCall = wsynth.genRunAsyncAt(classSynth, place, remoteClassGen.getClassType(), remoteMainRef); transCodes.addFast(asyncCall); transCodes.addResume(asyncCall); } else { //_pc = x; increase pc first try{ //check whether the frame contains pc field. For optimized finish frame and async frame, there is no pc field Stmt pcAssign = wsynth.genPCAssign(classSynth, prePcValue + 1); transCodes.addFast(pcAssign); transCodes.addResume(pcAssign); } catch(polyglot.types.NoMemberException e){ //Just ignore the pc assign statement if there is no pc field in the frame } Stmt atCall = wsynth.genRunAt(classSynth, place, remoteClassGen.getClassType(), remoteMainRef); transCodes.addFast(atCall); transCodes.addResume(atCall); transCodes.increasePC(); } return transCodes; } protected TransCodes transAsync(Stmt a, int prePcValue) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); AbstractWSClassGen asyncClassGen = genChildFrame(xts.AsyncFrame(), a, null); //fast List<Stmt> fastStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, fastMSynth, asyncClassGen); transCodes.addFast(fastStmts); // resume List<Stmt> resumeStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, resumeMSynth, asyncClassGen); transCodes.addResume(resumeStmts); transCodes.increasePC(); return transCodes; } /** * Transform one block code. If the code block is a complex code block, * translate it into a regular frame, and add corresponding codes into a new * block * * Else just only replace the local access to field access */ protected TransCodes transBlock(Block block, int prePcValue, String frameNamePrefix) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); AbstractWSClassGen blockClassGen = genChildFrame(xts.RegularFrame(), block, frameNamePrefix); //prepare child frame call; List<Stmt> fastStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, fastMSynth, blockClassGen); List<Stmt> resumeStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, resumeMSynth, blockClassGen); transCodes.addFast(fastStmts); transCodes.addResume(resumeStmts); transCodes.increasePC(); if(WSUtil.hasReturnStatement(block)){ //The code is after pc change transCodes.addFast(genReturnCheckStmt(true)); transCodes.addPostResume(genReturnCheckStmt(false)); } return transCodes; } /** * TryStmt: * Transform the whole try as one separate frame right now. * Try as one frame "E" frame * Try's body as a lower "B" frame * TryFrame * -->TransBodyFrame * * only has tryBlock as concurrent block. Then just call transBlock to transform this part */ protected TransCodes transTry(Try tryStmt, int prePcValue) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); AbstractWSClassGen tryClassGen = genChildFrame(xts.RegularFrame(), tryStmt, null); //FIXME: need understand the situation that a "return" appears in try's block //prepare child frame call; List<Stmt> fastStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, fastMSynth, tryClassGen); List<Stmt> resumeStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, resumeMSynth, tryClassGen); transCodes.addFast(fastStmts); transCodes.addResume(resumeStmts); transCodes.increasePC(); if(WSUtil.hasReturnStatement(tryStmt.tryBlock())){ //The code is after pc change transCodes.addFast(genReturnCheckStmt(true)); transCodes.addPostResume(genReturnCheckStmt(false)); } return transCodes; } protected TransCodes transSwitch(Switch switchStmt, int prePcValue) throws SemanticException { TransCodes transCodes = new TransCodes(prePcValue); AbstractWSClassGen switchClassGen = genChildFrame(xts.RegularFrame(), switchStmt, null); //prepare child frame call; List<Stmt> fastStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, fastMSynth, switchClassGen); List<Stmt> resumeStmts = wsynth.genInvocateFrameStmts(prePcValue + 1, classSynth, resumeMSynth, switchClassGen); transCodes.addFast(fastStmts); transCodes.addResume(resumeStmts); transCodes.increasePC(); if(WSUtil.hasReturnStatement(switchStmt)){ //The code is after pc change transCodes.addFast(genReturnCheckStmt(true)); transCodes.addPostResume(genReturnCheckStmt(false)); } return transCodes; } /** * Generate this stmt " if(returnFlag == true){ return result; } * * If a block contains return, and the block need to be transformed into a * separate frame, after the fast/slow call to the block, an additional * return check need to be added, to make sure if the return is executed in * the block frame, the caller need return Immediately. * * Fast: return in non method frame, and return result in method frame * Resume: always just return; * * @return * @throws SemanticException */ protected Stmt genReturnCheckStmt(boolean isFastPath) throws SemanticException { isReturnPathChanged = true; //has changed the original return path // return and reference Name returnFlagName = WSSynthesizer.RETURN_FLAG; Expr methodFrameRef = this.getFieldContainerRef(returnFlagName, xts.Boolean()); Expr returnFlagRef = synth.makeFieldAccess(compilerPos, methodFrameRef, returnFlagName, xct) .type(xts.Boolean()); Name resultName = WSSynthesizer.RETURN_VALUE; Expr resultRef = null; if (isFastPath && resultName != null && this instanceof WSMethodFrameClassGen) { // has return value && the current frame is method frame resultRef = synth.makeFieldAccess(compilerPos, methodFrameRef, resultName, xct); } // if(returnFlag == true){ // return result; //fast path in method frame // return; //resume path and non method frame // } // xnf.If(pos, cond, consequent, alternative) Expr returnCondition = xnf.Binary(compilerPos, returnFlagRef, Binary.EQ, synth.booleanValueExpr(true, compilerPos)).type(xts.Boolean()); Stmt returnCheck = xnf.If(compilerPos, returnCondition, resultRef == null ? xnf.Return(compilerPos) : xnf .Return(compilerPos, resultRef)); return returnCheck; } protected void genClassConstructor() throws SemanticException { wsynth.genClassConstructorType2Base(classSynth); } /* * Cannot inline RemoteMainFrame's fast path * @see x10.compiler.ws.codegen.AbstractWSClassGen#isFastPathInline() */ public boolean isFastPathInline(ClassType frameType){ if(xts.isSubtype(frameType, xts.MainFrame())){ return false; //cannot inline main frame } else{ return super.isFastPathInline(frameType); //default true; } } }