/** * (C) Copyright IBM Corp. 2010, 2015 * * Licensed 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 com.ibm.bi.dml.runtime.controlprogram; import java.util.ArrayList; import com.ibm.bi.dml.api.DMLScript; import com.ibm.bi.dml.hops.OptimizerUtils; import com.ibm.bi.dml.hops.recompile.Recompiler; import com.ibm.bi.dml.parser.DataIdentifier; import com.ibm.bi.dml.runtime.DMLRuntimeException; import com.ibm.bi.dml.runtime.DMLScriptException; import com.ibm.bi.dml.runtime.DMLUnsupportedOperationException; import com.ibm.bi.dml.runtime.controlprogram.context.ExecutionContext; import com.ibm.bi.dml.runtime.instructions.cp.Data; import com.ibm.bi.dml.utils.Statistics; public class FunctionProgramBlock extends ProgramBlock { protected ArrayList<ProgramBlock> _childBlocks; protected ArrayList<DataIdentifier> _inputParams; protected ArrayList<DataIdentifier> _outputParams; private boolean _recompileOnce = false; public FunctionProgramBlock( Program prog, ArrayList<DataIdentifier> inputParams, ArrayList<DataIdentifier> outputParams) throws DMLRuntimeException { super(prog); _childBlocks = new ArrayList<ProgramBlock>(); _inputParams = new ArrayList<DataIdentifier>(); for (DataIdentifier id : inputParams){ _inputParams.add(new DataIdentifier(id)); } _outputParams = new ArrayList<DataIdentifier>(); for (DataIdentifier id : outputParams){ _outputParams.add(new DataIdentifier(id)); } } public ArrayList<DataIdentifier> getInputParams(){ return _inputParams; } public ArrayList<DataIdentifier> getOutputParams(){ return _outputParams; } public void addProgramBlock(ProgramBlock childBlock) { _childBlocks.add(childBlock); } public void setChildBlocks( ArrayList<ProgramBlock> pbs) { _childBlocks = pbs; } public ArrayList<ProgramBlock> getChildBlocks() { return _childBlocks; } @Override public void execute(ExecutionContext ec) throws DMLRuntimeException, DMLUnsupportedOperationException { //dynamically recompile entire function body (according to function inputs) try { if( OptimizerUtils.ALLOW_DYN_RECOMPILATION && isRecompileOnce() && ParForProgramBlock.RESET_RECOMPILATION_FLAGs ) { long t0 = DMLScript.STATISTICS ? System.nanoTime() : 0; //note: it is important to reset the recompilation flags here // (1) it is safe to reset recompilation flags because a 'recompile_once' // function will be recompiled for every execution. // (2) without reset, there would be no benefit in recompiling the entire function LocalVariableMap tmp = (LocalVariableMap) ec.getVariables().clone(); Recompiler.recompileProgramBlockHierarchy(_childBlocks, tmp, _tid, true); if( DMLScript.STATISTICS ){ long t1 = System.nanoTime(); Statistics.incrementFunRecompileTime(t1-t0); Statistics.incrementFunRecompiles(); } } } catch(Exception ex) { throw new DMLRuntimeException("Error recompiling function body.", ex); } // for each program block try { for (int i=0 ; i < this._childBlocks.size() ; i++) { ec.updateDebugState(i); _childBlocks.get(i).execute(ec); } } catch (DMLScriptException e) { throw e; } catch (Exception e){ throw new DMLRuntimeException(this.printBlockErrorLocation() + "Error evaluating function program block", e); } // check return values checkOutputParameters(ec.getVariables()); } /** * * @param vars */ protected void checkOutputParameters( LocalVariableMap vars ) { for( DataIdentifier diOut : _outputParams ) { String varName = diOut.getName(); Data dat = vars.get( varName ); if( dat == null ) LOG.error("Function output "+ varName +" is missing."); else if( dat.getDataType() != diOut.getDataType() ) LOG.warn("Function output "+ varName +" has wrong data type: "+dat.getDataType()+"."); else if( dat.getValueType() != diOut.getValueType() ) LOG.warn("Function output "+ varName +" has wrong value type: "+dat.getValueType()+"."); } } public void setRecompileOnce( boolean flag ) { _recompileOnce = flag; } public boolean isRecompileOnce() { return _recompileOnce; } public void printMe() { for (ProgramBlock pb : this._childBlocks){ pb.printMe(); } } public String printBlockErrorLocation(){ return "ERROR: Runtime error in function program block generated from function statement block between lines " + _beginLine + " and " + _endLine + " -- "; } }