/* * 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.Binary; import polyglot.ast.Branch; import polyglot.ast.Case; import polyglot.ast.Expr; import polyglot.ast.Local; import polyglot.ast.Stmt; import polyglot.ast.Switch; import polyglot.ast.SwitchBlock; import polyglot.ast.SwitchElement; import polyglot.types.SemanticException; import x10.compiler.ws.util.AddIndirectLocalDeclareVisitor; import x10.compiler.ws.util.ClosureDefReinstantiator; import x10.compiler.ws.util.TransCodes; 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 switch class * */ public class WSSwitchClassGen extends WSRegularFrameClassGen { protected final Switch switchStmt; public WSSwitchClassGen(AbstractWSClassGen parent, Switch switchStmt) { super(parent, switchStmt, WSUtil.getSwitchClassName(parent.getClassName())); this.switchStmt = switchStmt; } /* This method is different to the regular frame's genTreeMethods, * The switch's transformation is very complex. Please refer the ppt design doc in X10 wiki * @see x10.compiler.ws.codegen.WSRegularFrameClassGen#genThreeMethods() */ @Override protected void genMethods() throws SemanticException { //now prepare the body synth CodeBlockSynth fastBodySynth = fastMSynth.getMethodBodySynth(switchStmt.position()); CodeBlockSynth resumeBodySynth = resumeMSynth.getMethodBodySynth(switchStmt.position()); CodeBlockSynth backBodySynth = backMSynth.getMethodBodySynth(switchStmt.position()); //First get the original switch's expr Expr orgSwitchExpr = (Expr) this.replaceLocalVarRefWithFieldAccess(switchStmt.expr()); //prepare fast/resume's first switch table Switch fastSwitch = switchStmt.expr(orgSwitchExpr); ArrayList<SwitchElement> fastSwitchElements = new ArrayList<SwitchElement>(); //sPC = pc; Expr pcRef = wsynth.genPCRef(classSynth); NewLocalVarSynth sPCLocalSynth = resumeBodySynth.createLocalVar(switchStmt.position(), pcRef); Local sPCRef = sPCLocalSynth.getLocal(); Switch resumePCSetSwitch = switchStmt.expr(orgSwitchExpr); ArrayList<SwitchElement> resumePCSetSwitchElements = new ArrayList<SwitchElement>(); //now prepare resume/back's switch synthesizer SwitchSynth resumeSwitchSynth = new SwitchSynth(xnf, xct, switchStmt.position(), sPCRef); SwitchSynth backSwitchSynth = new SwitchSynth(xnf, xct, switchStmt.position(), pcRef); //start to go over all the switch's conditions, and process them int pcValue = -1; for(SwitchElement se : switchStmt.elements()){ if(se instanceof Case){ //add case to the switch directly fastSwitchElements.add(se); resumePCSetSwitchElements.add(se); continue; } SwitchBlock sb = (SwitchBlock)se; if(sb.statements().size() == 0){ continue; //no statements, just continue; } //break processing; int sbStmtSize = sb.statements().size(); Stmt lastStmt = sb.statements().get(sbStmtSize - 1); boolean containsBreak = false; if(lastStmt instanceof Branch && ((Branch)lastStmt).kind() == Branch.BREAK){ containsBreak = true; ArrayList<Stmt> newSBStmts = new ArrayList<Stmt>(sb.statements()); newSBStmts.remove(sbStmtSize - 1); sb = xnf.SwitchBlock(sb.position(), newSBStmts); //new block without break; } //in this case, pc value should change pcValue++; //and need set one in the slowPCSetSwitchElements; Assign sPCAssign = (Assign) xnf.LocalAssign(compilerPos, sPCRef, Assign.ASSIGN, synth.intValueExpr(pcValue, compilerPos)).type(xts.Int()); Stmt sPCAssignS = xnf.Eval(compilerPos, sPCAssign); ArrayList<Stmt> sPCChangeStmts = new ArrayList<Stmt>(); sPCChangeStmts.add(sPCAssignS); //always need a break; other wise the sPC is not correct sPCChangeStmts.add(xnf.Break(compilerPos)); resumePCSetSwitchElements.add(xnf.SwitchBlock(compilerPos, sPCChangeStmts)); if(!WSUtil.isComplexCodeNode(sb, wts)){ //simple codes, just do local to sb = (SwitchBlock) replaceLocalVarRefWithFieldAccess(sb); List<Stmt> stmts = new ArrayList<Stmt>(sb.statements()); if(containsBreak) { stmts.add(xnf.Break(lastStmt.position())); } fastSwitchElements.add(xnf.SwitchBlock(sb.position(), stmts)); resumeSwitchSynth.insertStatementInCondition(pcValue, xnf.SwitchBlock(sb.position(), stmts)); } else{ TransCodes transCodes = transBlock(sb, pcValue, WSUtil .getBlockFrameClassName(className)); //fast add to fast switch List<Stmt> fastSS = transCodes.getFastStmts(); if(containsBreak) { fastSS.add(xnf.Break(lastStmt.position())); } fastSwitchElements.add(xnf.SwitchBlock(sb.position(), fastSS)); //now change the pc pcValue = transCodes.pcValue(); //should increase one; //slow add to slow resumeSwitchSynth.insertStatementsInCondition(pcValue, transCodes.getResumeStmts()); //the second part of the slow if(containsBreak){ resumeSwitchSynth.insertStatementInCondition(pcValue, xnf.Break(lastStmt.position())); } else{ //Definitely need add a ";" in the next case condition, so that it could switch to there; resumeSwitchSynth.insertStatementInCondition(pcValue, xnf.Empty(lastStmt.position())); } //back add to back { //nothing } } } //now formulate the fast switch and resumePCSetSwitch fastSwitch = fastSwitch.elements(fastSwitchElements); fastBodySynth.addStmt(fastSwitch); //then the resume resumePCSetSwitch = resumePCSetSwitch.elements(resumePCSetSwitchElements); //formulate the if; Expr checkSPCCond = xnf.Binary(compilerPos, sPCRef, Binary.EQ, synth.intValueExpr(0, compilerPos)).type(xts.Boolean()); Stmt ifStmt = xnf.If(compilerPos, checkSPCCond, resumePCSetSwitch); resumeBodySynth.addStmt(ifStmt); resumeBodySynth.addStmt(resumeSwitchSynth); //the switch //finally the back backBodySynth.addStmt(backSwitchSynth); } }