/* * 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.List; import polyglot.ast.Assign; import polyglot.ast.Block; import polyglot.ast.Eval; import polyglot.ast.Expr; import polyglot.ast.For; import polyglot.ast.ForInit; import polyglot.ast.ForUpdate; import polyglot.ast.LocalDecl; 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 for loop as one frame class * */ public class WSForLoopClassGen extends WSRegularFrameClassGen { protected final For forStmt; public WSForLoopClassGen(AbstractWSClassGen parent, For forStmt) { super(parent, forStmt.body(), WSUtil.getLoopClassName(parent.getClassName())); this.forStmt = forStmt; } /* This method is different to the regular frame's genTreeMethods, * since for loop will transform the for into while in slow path * @see x10.compiler.ws.codegen.WSRegularFrameClassGen#genThreeMethods() */ @Override protected void genMethods() throws SemanticException { //Firstly process all the initial, update, condition List<ForInit> forInits = new ArrayList<ForInit>(); for(ForInit fi : forStmt.inits()){ //in fact, the update could be an method call or something; if(fi instanceof LocalDecl){ fi = (ForInit) transLocalDecl((LocalDecl)fi); } if(fi instanceof Eval){ fi = (ForInit) this.replaceLocalVarRefWithFieldAccess(fi); } if(fi != null){ forInits.add(fi); } } Expr forCond = (Expr) this.replaceLocalVarRefWithFieldAccess(forStmt.cond()); List<ForUpdate> forUpdates = new ArrayList<ForUpdate>(); for(ForUpdate fu : forStmt.iters()){ //in fact, the update could be an method call or something; forUpdates.add((ForUpdate) replaceLocalVarRefWithFieldAccess(fu)); } //then transform the whole body Triple<CodeBlockSynth, SwitchSynth, SwitchSynth> bodyCodes = transformMethodBody(); //the results are just the bodies of fast/slow/back CodeBlockSynth fastForBlockSynth = 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); Expr pcRef = wsynth.genPCRef(classSynth); //now build the whole bodies { //fast For fastFS = forStmt.inits(forInits); fastFS = fastFS.cond(forCond); fastFS = fastFS.iters(forUpdates); fastFS = fastFS.body(fastForBlockSynth.close()); fastBodySynth.addStmt(fastFS); } { //slow //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 - create the switch statement //get the current pcValue ArrayList<Integer> switchTable = resumeSwitchSynth.getSwitchTable(); int pcValue = switchTable.get(switchTable.size() - 1); //special process, if the pcValue == 0, means there is no additional statements after the concurrent frame call //we need improve the pcValue to 1 pcValue = pcValue == 0 ? 1 : pcValue; //slow transform into a while //form while's body SwitchSynth whileSwitch = new SwitchSynth(xnf, xct, compilerPos, pcRef); //now insert condition on for(ForInit fi : forInits){ whileSwitch.insertStatementInCondition(0, fi); } //now change original condition //in fact, the condition should be put in -1 Expr returnCondition = xnf.Unary(compilerPos, forCond, Unary.NOT).type(xts.Boolean()); Stmt returnCheck = xnf.If(compilerPos, returnCondition, xnf.Return(compilerPos)); //now switch the original condition, and add a return whileSwitch.insertStatementInCondition(-1, returnCheck); whileSwitch.insertStatementsInCondition(-1, resumeSwitchSynth.getStmtsInCondtion(0)); //now processing all other cases' codes for(int i : resumeSwitchSynth.getSwitchTable()){ if(i == 0){ continue; //has processed } whileSwitch.insertStatementsInCondition(i, resumeSwitchSynth.getStmtsInCondtion(i)); pcValue = i; //assign the value to pcValue; } //finally process the original update and condition for(ForUpdate fu : forUpdates){ whileSwitch.insertStatementInCondition(pcValue, fu); } //now assign the pc ref to -1; Stmt pcChange = wsynth.genPCAssign(classSynth, -1); 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 break 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 slowWhile = xnf.While(compilerPos, synth.booleanValueExpr(true, compilerPos), whileBodySynth.genStmt()); resumeBodySynth.addStmt(slowWhile); } { backBodySynth.addStmt(backSwitchSynth.genStmt()); } } }