/* * This file is part of JOP, the Java Optimized Processor * see <http://www.jopdesign.com/> * * Copyright (C) 2010, Benedikt Huber (benedikt.huber@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.jopdesign.wcet.uppaal.translator; import com.jopdesign.common.MethodInfo; import com.jopdesign.common.code.ControlFlowGraph; import com.jopdesign.common.code.ControlFlowGraph.CFGNode; import com.jopdesign.common.code.LoopBound; import com.jopdesign.common.misc.MiscUtils; import com.jopdesign.wcet.WCETTool; import com.jopdesign.wcet.analysis.AnalysisContextLocal; import com.jopdesign.wcet.analysis.LocalAnalysis; import com.jopdesign.wcet.analysis.RecursiveWcetAnalysis; import com.jopdesign.wcet.analysis.WcetCost; import com.jopdesign.wcet.ipet.IPETConfig.CacheCostCalculationMethod; import com.jopdesign.wcet.uppaal.UppAalConfig; import com.jopdesign.wcet.uppaal.model.DuplicateKeyException; import com.jopdesign.wcet.uppaal.model.Location; import com.jopdesign.wcet.uppaal.model.Transition; import java.util.HashMap; import java.util.Map; /** * One-Template-Per-Method process translator * * @author Benedikt Huber <benedikt.huber@gmail.com> */ public class JavaOneProcessPerMethodTranslator extends JavaTranslator { public class InvokeViaSyncBuilder extends InvokeBuilder { public InvokeViaSyncBuilder(JavaTranslator mt, TemplateBuilder tBuilder) { super(mt, tBuilder, mt.cacheSim); } /* we need a few nodes for translating an invoke node * - A bbNode (wait, before invoking) * - An invokeNode (for waiting while executing the invoked method) * - Additionally when using a cache: * - A invokeMissNode (for waiting the miss of the invoked method) * with (bb -> invokeMissNode, invokeMissNode -> wait) * and (access (-> bb), guard (bb -> invokeMissNode), guard (bb -> invokeNode)) * - A returnAccessNode, a returnMissNode and a exitInvokeNode * (for waiting the miss of the returned method) * (non-Javadoc) * @see com.jopdesign.wcet.uppaal.translator.InvokeBuilder#translateInvoke(com.jopdesign.wcet.frontend.ControlFlowGraph.InvokeNode) */ @Override public SubAutomaton translateInvoke(MethodBuilder mBuilder, ControlFlowGraph.InvokeNode n, long staticWCET) { /* location for executing the code */ SubAutomaton basicBlock = mBuilder.createBasicBlock(n.getId(), staticWCET); Location startInvoke = basicBlock.getEntry(), finishInvoke; Location basicBlockNode = basicBlock.getExit(); /* location for waiting */ Location waitInvokeNode = tBuilder.createLocation("INVOKE_WAIT_" + n.getId()); simulateMethodInvocation(waitInvokeNode, n); /* If dynamic cache sim */ if (javaTranslator.getCacheSim().isDynamic()) { Location invokeMissNode = tBuilder.createLocation("INVOKE_MISS_" + n.getId()); Transition toInvokeHit = tBuilder.createTransition(basicBlockNode, waitInvokeNode); Transition toInvokeMiss = tBuilder.createTransition(basicBlockNode, invokeMissNode); tBuilder.createTransition(invokeMissNode, waitInvokeNode); simulateCacheAccess( n.receiverFlowGraph(), true, basicBlockNode, /* access cache on ingoing transitions */ toInvokeHit, /* if hit transition */ toInvokeMiss, /* if miss transition */ invokeMissNode); /* miss node */ Location returnAccessNode = tBuilder.createCommitedLocation("RETURN_ACCESS_" + n.getId()); Location returnMissNode = tBuilder.createLocation("RETURN_MISS_" + n.getId()); Location exitInvokeNode = tBuilder.createCommitedLocation("EXIT_INVOKE_" + n.getId()); tBuilder.createTransition(waitInvokeNode, returnAccessNode); Transition toReturnHit = tBuilder.createTransition(returnAccessNode, exitInvokeNode); Transition toReturnMiss = tBuilder.createTransition(returnAccessNode, returnMissNode); tBuilder.createTransition(returnMissNode, exitInvokeNode); simulateCacheAccess( n.invokerFlowGraph(), false, returnAccessNode, /* access cache on ingoing transitions */ toReturnHit, /* if hit transition */ toReturnMiss, /* if miss transition */ returnMissNode); /* miss node */ finishInvoke = exitInvokeNode; } else { tBuilder.createTransition(basicBlockNode, waitInvokeNode); finishInvoke = waitInvokeNode; } return new SubAutomaton(startInvoke, finishInvoke); } public void simulateMethodInvocation(Location waitInvokeLoc, ControlFlowGraph.InvokeNode n) { if (n.receiverFlowGraph().isLeafMethod() && config.collapseLeaves) { RecursiveWcetAnalysis<AnalysisContextLocal> ilpAn = new RecursiveWcetAnalysis<AnalysisContextLocal>(project, new LocalAnalysis()); WcetCost wcet = ilpAn.computeCost(n.getImplementingMethod(), new AnalysisContextLocal(CacheCostCalculationMethod.ALWAYS_HIT)); tBuilder.waitAtLocation(waitInvokeLoc, wcet.getCost()); } else { int mid = javaTranslator.getMethodID(n.getImplementingMethod()); tBuilder.getIncomingAttrs(waitInvokeLoc) .setSync(SystemBuilder.methodChannel(mid) + "!"); tBuilder.getOutgoingAttrs(waitInvokeLoc) .setSync(SystemBuilder.methodChannel(mid) + "?"); } } } private Map<MethodInfo, TemplateBuilder> processes = new HashMap<MethodInfo, TemplateBuilder>(); public JavaOneProcessPerMethodTranslator(UppAalConfig c, WCETTool p, MethodInfo root) { super(c, p, root); } @Override protected void translate() { systemBuilder.addMethodSynchChannels(methodInfos, this.methodIDs); String bbClock = systemBuilder.addProcessClock(0); /* For each method, create a process */ for (MethodInfo mi : this.methodInfos) { if (project.getCallGraph().isLeafMethod(mi) && config.collapseLeaves) continue; int pid = getMethodID(mi); TemplateBuilder tBuilder = new TemplateBuilder(config, MiscUtils.qEncode(mi.getFQMethodName()), pid, bbClock); recordLoops(mi, tBuilder); processes.put(mi, tBuilder); translateMethod(tBuilder, tBuilder.getTemplateAutomaton(), pid, mi, new InvokeViaSyncBuilder(this, tBuilder)); if (mi.equals(root)) { tBuilder.getInitial().setCommited(); tBuilder.addPostEnd(); } else { tBuilder.addSyncLoop(); } try { systemBuilder.addTemplate(pid, 0, tBuilder.getFinalTemplate()); } catch (DuplicateKeyException e) { throw new AssertionError("Unexpected exception when adding template: " + e.getMessage()); } } } private void recordLoops(MethodInfo mi, TemplateBuilder pb) { ControlFlowGraph cfg = project.getFlowGraph(mi); for (CFGNode hol : cfg.getLoopColoring().getHeadOfLoops()) { LoopBound bound = hol.getLoopBound(); int nesting = cfg.getLoopColoring().getLoopColor(hol).size(); pb.addLoop(hol, nesting, bound); } } }