/*
* 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 polyglot.ast.Assign;
import polyglot.ast.Block;
import polyglot.ast.Do;
import polyglot.ast.Expr;
import polyglot.ast.Loop;
import polyglot.ast.Stmt;
import polyglot.ast.Unary;
import polyglot.ast.While;
import polyglot.types.SemanticException;
import x10.compiler.ws.util.AddIndirectLocalDeclareVisitor;
import x10.compiler.ws.util.ClosureDefReinstantiator;
import x10.compiler.ws.util.Triple;
import x10.compiler.ws.util.WSUtil;
import x10.util.synthesizer.CodeBlockSynth;
import x10.util.synthesizer.InstanceCallSynth;
import x10.util.synthesizer.NewLocalVarSynth;
import x10.util.synthesizer.SwitchSynth;
/**
* @author Haichuan
*
* Generate the while & do loop as one frame class
*
*/
public class WSWhileDoLoopClassGen extends WSRegularFrameClassGen {
protected final Loop loopStmt;
public WSWhileDoLoopClassGen(AbstractWSClassGen parent, Loop loopStmt) {
super(parent, loopStmt.body(),
WSUtil.getLoopClassName(parent.getClassName()));
this.loopStmt = loopStmt;
}
/* This method is different to the regular frame's genTreeMethods,
* since loop will transform the loop into while in slow path
* @see x10.compiler.ws.codegen.WSRegularFrameClassGen#genThreeMethods()
*/
@Override
protected void genMethods() throws SemanticException {
Triple<CodeBlockSynth, SwitchSynth, SwitchSynth> bodyCodes = transformMethodBody();
//the results are just the bodies of fast/slow/back
CodeBlockSynth fastLoopBlockSynth = bodyCodes.first();
SwitchSynth resumeSwitchSynth = bodyCodes.second();
SwitchSynth backSwitchSynth = bodyCodes.third();
//now prepare the body synth
CodeBlockSynth fastBodySynth = fastMSynth.getMethodBodySynth(compilerPos);
CodeBlockSynth resumeBodySynth = resumeMSynth.getMethodBodySynth(compilerPos);
CodeBlockSynth backBodySynth = backMSynth.getMethodBodySynth(compilerPos);
//now processing all others about the loop
boolean isCondInFront = loopStmt instanceof While; //while's condition at the beginning,
Expr loopCondExpr = (Expr)this.replaceLocalVarRefWithFieldAccess(loopStmt.cond());
Expr pcRef = wsynth.genPCRef(classSynth);
//now build the whole bodies
{ //fast
if(isCondInFront){ //
While fastWhile = (While)loopStmt;
fastWhile = fastWhile.cond(loopCondExpr);
fastWhile = fastWhile.body(fastLoopBlockSynth.close());
fastBodySynth.addStmt(fastWhile);
}
else{
Do fastDo = (Do)loopStmt;
fastDo = fastDo.cond(loopCondExpr);
fastDo = fastDo.body(fastLoopBlockSynth.close());
fastBodySynth.addStmt(fastDo);
}
}
{ //resume
//just maintain as is switch condition,
//if while: condition check is in pc = 1;
//if do: condition check at the final
//Step 0 - Create the while's body
CodeBlockSynth whileBodySynth = new CodeBlockSynth(xnf, xct, compilerPos);
//prepare a boolean breaked Flag;
//In after each loop, the breaked will be set to false; And it is not set to false, it will breaked;
NewLocalVarSynth breakedFlagSynth = whileBodySynth.createLocalVar(compilerPos, synth.booleanValueExpr(true, compilerPos));
//Step 1 - prepare the return conditional check
Expr returnCondition = xnf.Unary(compilerPos, loopCondExpr, Unary.NOT).type(xts.Boolean());
Stmt returnCheck = xnf.If(compilerPos, returnCondition, xnf.Return(compilerPos));
//slow transform into a while
//form while's body
SwitchSynth whileSwitch = new SwitchSynth(xnf, xct, compilerPos, pcRef);
if(isCondInFront){
whileSwitch.insertStatementInCondition(0, returnCheck);
}
//copy all switch table;
int pcValue = 0;
for(int i : resumeSwitchSynth.getSwitchTable()){
whileSwitch.insertStatementsInCondition(i, resumeSwitchSynth.getStmtsInCondtion(i));
pcValue = i; //assign the value to pcValue;
}
//special process, in case only one switch table item
pcValue = (pcValue == 0) ? 1 : pcValue;
if(!isCondInFront){
whileSwitch.insertStatementInCondition(pcValue, returnCheck);
}
Stmt pcChange = wsynth.genPCAssign(classSynth, 0);
whileSwitch.insertStatementInCondition(pcValue, pcChange);
//And set the breaked flag as false
Stmt breakedFalse = xnf.Eval(compilerPos, xnf.LocalAssign(compilerPos, breakedFlagSynth.getLocal(), Assign.ASSIGN,
synth.booleanValueExpr(false, compilerPos).type(breakedFlagSynth.getLocal().type())));
whileSwitch.insertStatementInCondition(pcValue, breakedFalse);
//Step 2: - Create the final breaked check, and add all into while bodySynth
whileBodySynth.addStmt(whileSwitch);
//if(breakedFlag) break;
//Expr breakedCondition = xnf.Binary(compilerPos, returnFlagRef, Binary.EQ, synth.booleanValueExpr(true, compilerPos)).type(xts.Boolean());
Stmt breakedCheck = xnf.If(compilerPos, breakedFlagSynth.getLocal().type(xts.Boolean()), xnf.Break(compilerPos));
whileBodySynth.addStmt(breakedCheck);
While resumeWhile = xnf.While(compilerPos, synth.booleanValueExpr(true, compilerPos), whileBodySynth.genStmt());
resumeBodySynth.addStmt(resumeWhile);
}
{
backBodySynth.addStmt(backSwitchSynth.genStmt());
}
}
}