blob: 12a8369e558248b189c5370f836896fcda5bb45b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sysml.parser;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.sysml.api.DMLScript;
import org.apache.sysml.conf.DMLConfig;
import org.apache.sysml.lops.LopProperties;
import org.apache.sysml.lops.Lop;
import org.apache.sysml.lops.LopsException;
import org.apache.sysml.lops.compile.Dag;
import org.apache.sysml.parser.Expression.DataType;
import org.apache.sysml.runtime.DMLRuntimeException;
import org.apache.sysml.runtime.controlprogram.ExternalFunctionProgramBlock;
import org.apache.sysml.runtime.controlprogram.ExternalFunctionProgramBlockCP;
import org.apache.sysml.runtime.controlprogram.ForProgramBlock;
import org.apache.sysml.runtime.controlprogram.FunctionProgramBlock;
import org.apache.sysml.runtime.controlprogram.IfProgramBlock;
import org.apache.sysml.runtime.controlprogram.ParForProgramBlock;
import org.apache.sysml.runtime.controlprogram.Program;
import org.apache.sysml.runtime.controlprogram.ProgramBlock;
import org.apache.sysml.runtime.controlprogram.WhileProgramBlock;
import org.apache.sysml.runtime.controlprogram.parfor.ProgramConverter;
import org.apache.sysml.runtime.instructions.CPInstructionParser;
import org.apache.sysml.runtime.instructions.Instruction;
public class DMLProgram
{
private ArrayList<StatementBlock> _blocks;
private HashMap<String, FunctionStatementBlock> _functionBlocks;
private HashMap<String,DMLProgram> _namespaces;
public static String DEFAULT_NAMESPACE = ".defaultNS";
public static String INTERNAL_NAMESPACE = "_internal"; // used for multi-return builtin functions
private static final Log LOG = LogFactory.getLog(DMLProgram.class.getName());
public DMLProgram(){
_blocks = new ArrayList<StatementBlock>();
_functionBlocks = new HashMap<String,FunctionStatementBlock>();
_namespaces = new HashMap<String,DMLProgram>();
}
public HashMap<String,DMLProgram> getNamespaces(){
return _namespaces;
}
public void addStatementBlock(StatementBlock b, int pos) {
_blocks.add(pos,b) ;
}
public void addStatementBlock(StatementBlock b){
_blocks.add(b);
}
public int getNumStatementBlocks(){
return _blocks.size();
}
/**
*
* @param fkey function key as concatenation of namespace and function name
* (see DMLProgram.constructFunctionKey)
* @return
*/
public FunctionStatementBlock getFunctionStatementBlock(String fkey) {
String[] tmp = splitFunctionKey(fkey);
return getFunctionStatementBlock(tmp[0], tmp[1]);
}
public FunctionStatementBlock getFunctionStatementBlock(String namespaceKey, String functionName) {
DMLProgram namespaceProgram = this.getNamespaces().get(namespaceKey);
if (namespaceProgram == null)
return null;
// for the namespace DMLProgram, get the specified function (if exists) in its current namespace
FunctionStatementBlock retVal = namespaceProgram._functionBlocks.get(functionName);
return retVal;
}
public HashMap<String, FunctionStatementBlock> getFunctionStatementBlocks(String namespaceKey) throws LanguageException{
DMLProgram namespaceProgram = this.getNamespaces().get(namespaceKey);
if (namespaceProgram == null){
LOG.error("ERROR: namespace " + namespaceKey + " is undefined");
throw new LanguageException("ERROR: namespace " + namespaceKey + " is undefined");
}
// for the namespace DMLProgram, get the functions in its current namespace
return namespaceProgram._functionBlocks;
}
public ArrayList<FunctionStatementBlock> getFunctionStatementBlocks()
throws LanguageException
{
ArrayList<FunctionStatementBlock> ret = new ArrayList<FunctionStatementBlock>();
for( DMLProgram nsProg : _namespaces.values() )
ret.addAll(nsProg._functionBlocks.values());
return ret;
}
public void addFunctionStatementBlock( String namespace, String fname, FunctionStatementBlock fsb )
throws LanguageException
{
DMLProgram namespaceProgram = this.getNamespaces().get(namespace);
if (namespaceProgram == null)
throw new LanguageException( "Namespace does not exist." );
namespaceProgram._functionBlocks.put(fname, fsb);
}
public ArrayList<StatementBlock> getStatementBlocks(){
return _blocks;
}
public void setStatementBlocks(ArrayList<StatementBlock> passed){
_blocks = passed;
}
public StatementBlock getStatementBlock(int i){
return _blocks.get(i);
}
public void setStatementBlock(int i, StatementBlock sb) {
_blocks.set(i, sb);
}
public void mergeStatementBlocks(){
_blocks = StatementBlock.mergeStatementBlocks(_blocks);
}
public String toString(){
StringBuilder sb = new StringBuilder();
// for each namespace, display all functions
for (String namespaceKey : this.getNamespaces().keySet()){
sb.append("NAMESPACE = " + namespaceKey + "\n");
DMLProgram namespaceProg = this.getNamespaces().get(namespaceKey);
sb.append("FUNCTIONS = ");
for (FunctionStatementBlock fsb : namespaceProg._functionBlocks.values()){
sb.append(fsb);
sb.append(", ");
}
sb.append("\n");
sb.append("********************************** \n");
}
sb.append("******** MAIN SCRIPT BODY ******** \n");
for (StatementBlock b : _blocks){
sb.append(b);
sb.append("\n");
}
sb.append("********************************** \n");
return sb.toString();
}
public Program getRuntimeProgram(DMLConfig config) throws IOException, LanguageException, DMLRuntimeException, LopsException {
// constructor resets the set of registered functions
Program rtprog = new Program();
// for all namespaces, translate function statement blocks into function program blocks
for (String namespace : _namespaces.keySet()){
for (String fname : getFunctionStatementBlocks(namespace).keySet()){
// add program block to program
FunctionStatementBlock fsb = getFunctionStatementBlocks(namespace).get(fname);
FunctionProgramBlock rtpb = (FunctionProgramBlock)createRuntimeProgramBlock(rtprog, fsb, config);
rtprog.addFunctionProgramBlock(namespace, fname, rtpb);
rtpb.setRecompileOnce( fsb.isRecompileOnce() );
}
}
// for each top-level block
for (StatementBlock sb : _blocks) {
// add program block to program
ProgramBlock rtpb = createRuntimeProgramBlock(rtprog, sb, config);
rtprog.addProgramBlock(rtpb);
}
return rtprog ;
}
/**
*
* @param prog
* @param sb
* @param config
* @return
* @throws IOException
* @throws LopsException
* @throws DMLRuntimeException
*/
public ProgramBlock createRuntimeProgramBlock(Program prog, StatementBlock sb, DMLConfig config)
throws IOException, LopsException, DMLRuntimeException
{
Dag<Lop> dag = null;
Dag<Lop> pred_dag = null;
ArrayList<Instruction> instruct;
ArrayList<Instruction> pred_instruct = null;
ProgramBlock retPB = null;
// process While Statement - add runtime program blocks to program
if (sb instanceof WhileStatementBlock){
// create DAG for loop predicates
pred_dag = new Dag<Lop>();
((WhileStatementBlock) sb).get_predicateLops().addToDag(pred_dag);
// create instructions for loop predicates
pred_instruct = new ArrayList<Instruction>();
ArrayList<Instruction> pInst = pred_dag.getJobs(null, config);
for (Instruction i : pInst ) {
pred_instruct.add(i);
}
// create while program block
WhileProgramBlock rtpb = new WhileProgramBlock(prog, pred_instruct);
if (rtpb.getPredicateResultVar() == null) {
// e.g case : WHILE(continue)
if ( ((WhileStatementBlock) sb).get_predicateLops().getExecLocation() == LopProperties.ExecLocation.Data ) {
String resultVar = ((WhileStatementBlock) sb).get_predicateLops().getOutputParameters().getLabel();
rtpb.setPredicateResultVar( resultVar );
}
else {
LOG.error(sb.printBlockErrorLocation() + "Error in translating the WHILE predicate.");
throw new LopsException(sb.printBlockErrorLocation() + "Error in translating the WHILE predicate.");
}
}
//// process the body of the while statement block ////
WhileStatementBlock wsb = (WhileStatementBlock)sb;
if (wsb.getNumStatements() > 1){
LOG.error(wsb.printBlockErrorLocation() + "WhileStatementBlock should only have 1 statement");
throw new LopsException(wsb.printBlockErrorLocation() + "WhileStatementBlock should only have 1 statement");
}
WhileStatement wstmt = (WhileStatement)wsb.getStatement(0);
for (StatementBlock sblock : wstmt.getBody()){
// process the body
ProgramBlock childBlock = createRuntimeProgramBlock(prog, sblock, config);
rtpb.addProgramBlock(childBlock);
}
// check there are actually Lops in to process (loop stmt body will not have any)
if (wsb.getLops() != null && !wsb.getLops().isEmpty() ){
LOG.error(wsb.printBlockErrorLocation() + "WhileStatementBlock should have no Lops");
throw new LopsException(wsb.printBlockErrorLocation() + "WhileStatementBlock should have no Lops");
}
retPB = rtpb;
//post processing for generating missing instructions
//retPB = verifyAndCorrectProgramBlock(sb.liveIn(), sb.liveOut(), sb._kill, retPB);
// add statement block
retPB.setStatementBlock(sb);
// add location information
retPB.setAllPositions(sb.getBeginLine(), sb.getBeginColumn(), sb.getEndLine(), sb.getEndColumn());
}
// process If Statement - add runtime program blocks to program
else if (sb instanceof IfStatementBlock){
// create DAG for loop predicates
pred_dag = new Dag<Lop>();
((IfStatementBlock) sb).get_predicateLops().addToDag(pred_dag);
// create instructions for loop predicates
pred_instruct = new ArrayList<Instruction>();
ArrayList<Instruction> pInst = pred_dag.getJobs(null, config);
for (Instruction i : pInst ) {
pred_instruct.add(i);
}
// create if program block
IfProgramBlock rtpb = new IfProgramBlock(prog, pred_instruct);
if (rtpb.getPredicateResultVar() == null ) {
// e.g case : If(continue)
if ( ((IfStatementBlock) sb).get_predicateLops().getExecLocation() == LopProperties.ExecLocation.Data ) {
String resultVar = ((IfStatementBlock) sb).get_predicateLops().getOutputParameters().getLabel();
rtpb.setPredicateResultVar( resultVar );
}
else {
LOG.error(sb.printBlockErrorLocation() + "Error in translating the IF predicate.");
throw new LopsException(sb.printBlockErrorLocation() + "Error in translating the IF predicate.");
}
}
// process the body of the if statement block
IfStatementBlock isb = (IfStatementBlock)sb;
if (isb.getNumStatements() > 1){
LOG.error(isb.printBlockErrorLocation() + "IfStatementBlock should have only 1 statement");
throw new LopsException(isb.printBlockErrorLocation() + "IfStatementBlock should have only 1 statement");
}
IfStatement istmt = (IfStatement)isb.getStatement(0);
// process the if body
for (StatementBlock sblock : istmt.getIfBody()){
ProgramBlock childBlock = createRuntimeProgramBlock(prog, sblock, config);
rtpb.addProgramBlockIfBody(childBlock);
}
// process the else body
for (StatementBlock sblock : istmt.getElseBody()){
ProgramBlock childBlock = createRuntimeProgramBlock(prog, sblock, config);
rtpb.addProgramBlockElseBody(childBlock);
}
// check there are actually Lops in to process (loop stmt body will not have any)
if (isb.getLops() != null && !isb.getLops().isEmpty() ){
LOG.error(isb.printBlockErrorLocation() + "IfStatementBlock should have no Lops");
throw new LopsException(isb.printBlockErrorLocation() + "IfStatementBlock should have no Lops");
}
retPB = rtpb;
//post processing for generating missing instructions
//retPB = verifyAndCorrectProgramBlock(sb.liveIn(), sb.liveOut(), sb._kill, retPB);
// add statement block
retPB.setStatementBlock(sb);
// add location information
retPB.setAllPositions(sb.getBeginLine(), sb.getBeginColumn(), sb.getEndLine(), sb.getEndColumn());
}
// process For Statement - add runtime program blocks to program
// NOTE: applies to ForStatementBlock and ParForStatementBlock
else if (sb instanceof ForStatementBlock)
{
ForStatementBlock fsb = (ForStatementBlock) sb;
// create DAGs for loop predicates
Dag<Lop> fromDag = new Dag<Lop>();
Dag<Lop> toDag = new Dag<Lop>();
Dag<Lop> incrementDag = new Dag<Lop>();
if( fsb.getFromHops()!=null )
fsb.getFromLops().addToDag(fromDag);
if( fsb.getToHops()!=null )
fsb.getToLops().addToDag(toDag);
if( fsb.getIncrementHops()!=null )
fsb.getIncrementLops().addToDag(incrementDag);
// create instructions for loop predicates
ArrayList<Instruction> fromInstructions = fromDag.getJobs(null, config);
ArrayList<Instruction> toInstructions = toDag.getJobs(null, config);
ArrayList<Instruction> incrementInstructions = incrementDag.getJobs(null, config);
// create for program block
String sbName = null;
ForProgramBlock rtpb = null;
IterablePredicate iterPred = fsb.getIterPredicate();
String [] iterPredData= IterablePredicate.createIterablePredicateVariables(iterPred.getIterVar().getName(),
fsb.getFromLops(), fsb.getToLops(), fsb.getIncrementLops());
if( sb instanceof ParForStatementBlock )
{
sbName = "ParForStatementBlock";
rtpb = new ParForProgramBlock(prog, iterPredData,iterPred.getParForParams());
ParForProgramBlock pfrtpb = (ParForProgramBlock)rtpb;
pfrtpb.setResultVariables( ((ParForStatementBlock)sb).getResultVariables() );
pfrtpb.setStatementBlock((ParForStatementBlock)sb); //used for optimization and creating unscoped variables
}
else //ForStatementBlock
{
sbName = "ForStatementBlock";
rtpb = new ForProgramBlock(prog, iterPredData);
}
rtpb.setFromInstructions( fromInstructions );
rtpb.setToInstructions( toInstructions );
rtpb.setIncrementInstructions( incrementInstructions );
rtpb.setIterablePredicateVars( iterPredData );
// process the body of the for statement block
if (fsb.getNumStatements() > 1){
LOG.error(fsb.printBlockErrorLocation() + " " + sbName + " should have 1 statement" );
throw new LopsException(fsb.printBlockErrorLocation() + " " + sbName + " should have 1 statement" );
}
ForStatement fs = (ForStatement)fsb.getStatement(0);
for (StatementBlock sblock : fs.getBody()){
ProgramBlock childBlock = createRuntimeProgramBlock(prog, sblock, config);
rtpb.addProgramBlock(childBlock);
}
// check there are actually Lops in to process (loop stmt body will not have any)
if (fsb.getLops() != null && !fsb.getLops().isEmpty()){
LOG.error(fsb.printBlockErrorLocation() + sbName + " should have no Lops" );
throw new LopsException(fsb.printBlockErrorLocation() + sbName + " should have no Lops" );
}
retPB = rtpb;
//post processing for generating missing instructions
//retPB = verifyAndCorrectProgramBlock(sb.liveIn(), sb.liveOut(), sb._kill, retPB);
// add statement block
retPB.setStatementBlock(sb);
// add location information
retPB.setAllPositions(sb.getBeginLine(), sb.getBeginColumn(), sb.getEndLine(), sb.getEndColumn());
}
// process function statement block - add runtime program blocks to program
else if (sb instanceof FunctionStatementBlock){
FunctionStatementBlock fsb = (FunctionStatementBlock)sb;
if (fsb.getNumStatements() > 1){
LOG.error(fsb.printBlockErrorLocation() + "FunctionStatementBlock should only have 1 statement");
throw new LopsException(fsb.printBlockErrorLocation() + "FunctionStatementBlock should only have 1 statement");
}
FunctionStatement fstmt = (FunctionStatement)fsb.getStatement(0);
FunctionProgramBlock rtpb = null;
if (fstmt instanceof ExternalFunctionStatement) {
// create external function program block
String execType = ((ExternalFunctionStatement) fstmt)
.getOtherParams().get(ExternalFunctionStatement.EXEC_TYPE);
boolean isCP = (execType.equals(ExternalFunctionStatement.IN_MEMORY)) ? true : false;
String scratchSpaceLoc = null;
try {
scratchSpaceLoc = config.getTextValue(DMLConfig.SCRATCH_SPACE);
} catch (Exception e){
LOG.error(fsb.printBlockErrorLocation() + "could not retrieve parameter " + DMLConfig.SCRATCH_SPACE + " from DMLConfig");
}
StringBuilder buff = new StringBuilder();
buff.append(scratchSpaceLoc);
buff.append(Lop.FILE_SEPARATOR);
buff.append(Lop.PROCESS_PREFIX);
buff.append(DMLScript.getUUID());
buff.append(Lop.FILE_SEPARATOR);
buff.append(ProgramConverter.CP_ROOT_THREAD_ID);
buff.append(Lop.FILE_SEPARATOR);
buff.append("PackageSupport");
buff.append(Lop.FILE_SEPARATOR);
String basedir = buff.toString();
if( isCP )
{
rtpb = new ExternalFunctionProgramBlockCP(prog,
fstmt.getInputParams(), fstmt.getOutputParams(),
((ExternalFunctionStatement) fstmt).getOtherParams(),
basedir );
}
else
{
rtpb = new ExternalFunctionProgramBlock(prog,
fstmt.getInputParams(), fstmt.getOutputParams(),
((ExternalFunctionStatement) fstmt).getOtherParams(),
basedir);
}
if (!fstmt.getBody().isEmpty()){
LOG.error(fstmt.printErrorLocation() + "ExternalFunctionStatementBlock should have no statement blocks in body");
throw new LopsException(fstmt.printErrorLocation() + "ExternalFunctionStatementBlock should have no statement blocks in body");
}
}
else
{
// create function program block
rtpb = new FunctionProgramBlock(prog, fstmt.getInputParams(), fstmt.getOutputParams());
// process the function statement body
for (StatementBlock sblock : fstmt.getBody()){
// process the body
ProgramBlock childBlock = createRuntimeProgramBlock(prog, sblock, config);
rtpb.addProgramBlock(childBlock);
}
}
// check there are actually Lops in to process (loop stmt body will not have any)
if (fsb.getLops() != null && !fsb.getLops().isEmpty()){
LOG.error(fsb.printBlockErrorLocation() + "FunctionStatementBlock should have no Lops");
throw new LopsException(fsb.printBlockErrorLocation() + "FunctionStatementBlock should have no Lops");
}
retPB = rtpb;
// add location information
retPB.setAllPositions(sb.getBeginLine(), sb.getBeginColumn(), sb.getEndLine(), sb.getEndColumn());
}
else {
// handle general case
ProgramBlock rtpb = new ProgramBlock(prog);
// DAGs for Lops
dag = new Dag<Lop>();
// check there are actually Lops in to process (loop stmt body will not have any)
if (sb.getLops() != null && !sb.getLops().isEmpty()){
for (Lop l : sb.getLops()) {
l.addToDag(dag);
}
// Instructions for Lobs DAGs
instruct = dag.getJobs(sb, config);
rtpb.addInstructions(instruct);
}
/*// TODO: check with Doug
// add instruction for a function call
if (sb.getFunctionCallInst() != null){
rtpb.addInstruction(sb.getFunctionCallInst());
}*/
retPB = rtpb;
//post processing for generating missing instructions
//retPB = verifyAndCorrectProgramBlock(sb.liveIn(), sb.liveOut(), sb._kill, retPB);
// add statement block
retPB.setStatementBlock(sb);
// add location information
retPB.setAllPositions(sb.getBeginLine(), sb.getBeginColumn(), sb.getEndLine(), sb.getEndColumn());
}
return retPB;
}
/**
* Post processing of each created program block in order to adhere to livein/liveout
* (currently needed for cleanup (especially for caching) of intermediate results if the last datasink
* is an external function because instructions of external functions are created outside hops/lops,
* e.g., X=..., Y=fun(X) and X is not used afterwards )
*
* NOTES:
* (1) Rule1: checking livein and liveout is sufficient because the last external function is in its own
* programblock anyway.
* (2) as we cannot efficiently distinguish if the problematic var is created by an external function
* or some other instruction, we generate RMVAR instructions although for vars created by non-CP
* external functions RMFILEVAR instructions are required. However, all remaining files in scratch_space
* are cleaned after execution anyway.
* (3) As an alternative to doing rule 2, we could also check for existing objects in createvar and function invocation
* (or generic at program block level) and remove objects of previous iterations accordingly (but objects of last iteration
* would still require separate cleanup).
*
* TODO: MB: external function invocations should become hops/lops as well (see instruction gen in DMLTranslator),
* (currently not possible at Hops/Lops level due the requirement of multiple outputs for functions)
* TODO: MB: we should in general always leverage livein/liveout during hops/lops generation.
* TODO: MB: verify and correct can be removed once everything is integrated in hops/lops generation
*
* @param in
* @param out
* @param pb
* @return
* @throws DMLRuntimeException
*/
@SuppressWarnings("unused")
private ProgramBlock verifyAndCorrectProgramBlock(VariableSet in, VariableSet out, VariableSet kill, ProgramBlock pb)
throws DMLRuntimeException
{
//RULE 1: if in IN and not in OUT, then there should be an rmvar or rmfilevar inst
//(currently required for specific cases of external functions)
for( String varName : in.getVariableNames() )
if( !out.containsVariable(varName) )
{
DataType dt = in.getVariable(varName).getDataType();
if( !(dt==DataType.MATRIX || dt==DataType.UNKNOWN) )
continue; //skip rm instructions for non-matrix objects
boolean foundRMInst = rContainsRMInstruction(pb, varName);
if( !foundRMInst )
{
//create RMVAR instruction and put it into the programblock
Instruction inst = createCleanupInstruction(varName);
inst.setLocation(in.getVariable(varName));
addCleanupInstruction(pb, inst);
LOG.trace("Adding instruction (r1) "+inst.toString());
}
}
//RULE 2: if in KILL and not in IN and not in OUT, then there should be an rmvar or rmfilevar inst
//(currently required for specific cases of nested loops)
for( String varName : kill.getVariableNames() )
if( (!in.containsVariable(varName)) && (!out.containsVariable(varName)) )
{
DataType dt = kill.getVariable(varName).getDataType();
if( !(dt==DataType.MATRIX || dt==DataType.UNKNOWN) )
continue; //skip rm instructions for non-matrix objects
boolean foundRMInst = rContainsRMInstruction(pb, varName);
if( !foundRMInst )
{
//create RMVAR instruction and put it into the programblock
Instruction inst = createCleanupInstruction(varName);
inst.setLocation(kill.getVariable(varName));
//System.out.println("add rvar rule2 "+inst.toString());
addCleanupInstruction(pb, inst);
LOG.trace("Adding instruction (r2) "+inst.toString());
}
}
return pb;
}
private Instruction createCleanupInstruction(String varName)
throws DMLRuntimeException
{
//(example "CP+Lops.OPERAND_DELIMITOR+rmvar+Lops.OPERAND_DELIMITOR+Var7")
StringBuilder sb = new StringBuilder();
sb.append("CP");
sb.append(Lop.OPERAND_DELIMITOR);
sb.append("rmvar");
sb.append(Lop.OPERAND_DELIMITOR);
sb.append(varName);
String str = sb.toString();
Instruction inst = CPInstructionParser.parseSingleInstruction( str );
return inst;
}
/**
* Determines if the given program block includes a RMVAR or RMFILEVAR
* instruction for the given varName.
*
* @param pb
* @param varName
* @return
*/
private boolean rContainsRMInstruction(ProgramBlock pb, String varName)
{
if (pb instanceof WhileProgramBlock)
{
WhileProgramBlock tmp = (WhileProgramBlock)pb;
for( ProgramBlock c : tmp.getChildBlocks() )
if( rContainsRMInstruction(c, varName) )
return true;
}
else if (pb instanceof IfProgramBlock)
{
IfProgramBlock tmp = (IfProgramBlock)pb;
for( ProgramBlock c : tmp.getChildBlocksIfBody() )
if( rContainsRMInstruction(c, varName) )
return true;
for( ProgramBlock c : tmp.getChildBlocksElseBody() )
if( rContainsRMInstruction(c, varName) )
return true;
}
else if (pb instanceof ForProgramBlock) //includes ParFORProgramBlock
{
ForProgramBlock tmp = (ForProgramBlock)pb;
for( ProgramBlock c : tmp.getChildBlocks() )
if( rContainsRMInstruction(c, varName) )
return true;
}
else if ( pb instanceof FunctionProgramBlock ) //includes ExternalFunctionProgramBlock and ExternalFunctionProgramBlockCP)
{
//do nothing
}
else
{
for( Instruction inst : pb.getInstructions() )
{
String instStr = inst.toString();
if( instStr.contains("rmfilevar"+Lop.OPERAND_DELIMITOR+varName)
|| instStr.contains("rmvar"+Lop.OPERAND_DELIMITOR+varName) )
{
return true;
}
}
}
return false;
}
/**
* Adds the generated cleanup RMVAR instruction to the given program block.
* In case of generic (last-level) programblocks it is added to the end of
* the list of instructions, while for complex program blocks it is added to
* the end of the list of exit instructions.
*
* @param pb
* @param inst
* @throws DMLRuntimeException
*/
private void addCleanupInstruction( ProgramBlock pb, Instruction inst )
throws DMLRuntimeException
{
//System.out.println("Adding rm var instructions: "+inst.toString());
if (pb instanceof WhileProgramBlock)
{
WhileProgramBlock wpb = (WhileProgramBlock)pb;
ArrayList<ProgramBlock> childs = wpb.getChildBlocks();
if( !childs.get(childs.size()-1).getInstructions().isEmpty() ) //generic last level pb
childs.get(childs.size()-1).addInstruction(inst);
else{
ProgramBlock pbNew = new ProgramBlock(pb.getProgram());
pbNew.addInstruction(inst);
childs.add(pbNew);
}
}
else if (pb instanceof ForProgramBlock) //includes ParFORProgramBlock
{
ForProgramBlock wpb = (ForProgramBlock)pb;
ArrayList<ProgramBlock> childs = wpb.getChildBlocks();
if( !childs.get(childs.size()-1).getInstructions().isEmpty() ) //generic last level pb
childs.get(childs.size()-1).addInstruction(inst);
else{
ProgramBlock pbNew = new ProgramBlock(pb.getProgram());
pbNew.addInstruction(inst);
childs.add(pbNew);
}
}
else if (pb instanceof IfProgramBlock)
((IfProgramBlock)pb).addExitInstruction(inst);
else if ( pb instanceof FunctionProgramBlock ) //includes ExternalFunctionProgramBlock and ExternalFunctionProgramBlockCP)
; //do nothing
else
{
pb.addInstruction(inst); //add inst at end of pb
}
}
/**
*
* @param fnamespace
* @param fname
* @return
*/
public static String constructFunctionKey(String fnamespace, String fname)
{
return fnamespace + Program.KEY_DELIM + fname;
}
/**
*
* @param fkey
* @return
*/
public static String[] splitFunctionKey(String fkey)
{
return fkey.split(Program.KEY_DELIM);
}
}