/// <summary> /// Excecute an arbitrary depth replication using the full slow path algorithm /// </summary> /// <param name="functionEndPoint"> </param> /// <param name="c"></param> /// <param name="formalParameters"></param> /// <param name="replicationInstructions"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <returns></returns> private StackValue ExecWithRISlowPath( List<FunctionEndPoint> functionEndPoint, Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) { if (runtimeCore.Options.ExecutionMode == ExecutionMode.Parallel) throw new NotImplementedException("Parallel mode disabled: {BF417AD5-9EA9-4292-ABBC-3526FC5A149E}"); //Recursion base case if (replicationInstructions.Count == 0) { return ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, runtimeCore, funcGroup, previousTraceData, newTraceData); } //Get the replication instruction that this call will deal with ReplicationInstruction ri = replicationInstructions[0]; if (ri.Zipped) { ZipAlgorithm algorithm = ri.ZipAlgorithm; //For each item in this plane, an array of the length of the minimum will be constructed //The size of the array will be the minimum size of the passed arrays List<int> repIndecies = ri.ZipIndecies; //this will hold the heap elements for all the arrays that are going to be replicated over List<StackValue[]> parameters = new List<StackValue[]>(); int retSize; switch (algorithm) { case ZipAlgorithm.Shortest: retSize = Int32.MaxValue; //Search to find the smallest break; case ZipAlgorithm.Longest: retSize = Int32.MinValue; //Search to find the largest break; default: throw new ReplicationCaseNotCurrentlySupported(Resources.AlgorithmNotSupported); } bool hasEmptyArg = false; foreach (int repIndex in repIndecies) { StackValue[] subParameters = null; if (formalParameters[repIndex].IsArray) { subParameters = runtimeCore.Heap.ToHeapObject<DSArray>(formalParameters[repIndex]).Values.ToArray(); } else { subParameters = new StackValue[] { formalParameters[repIndex] }; } parameters.Add(subParameters); if (subParameters.Length == 0) hasEmptyArg = true; switch (algorithm) { case ZipAlgorithm.Shortest: retSize = Math.Min(retSize, subParameters.Length); //We need the smallest array break; case ZipAlgorithm.Longest: retSize = Math.Max(retSize, subParameters.Length); //We need the longest array break; } } // If we're being asked to replicate across an empty list // then it's always going to be zero, as there will never be any // data to pass to that parameter. if (hasEmptyArg) retSize = 0; StackValue[] retSVs = new StackValue[retSize]; SingleRunTraceData retTrace = newTraceData; retTrace.NestedData = new List<SingleRunTraceData>(); //this will shadow the SVs as they are created //Populate out the size of the list with default values //@TODO:Luke perf optimisation here for (int i = 0; i < retSize; i++) retTrace.NestedData.Add(new SingleRunTraceData()); for (int i = 0; i < retSize; i++) { SingleRunTraceData lastExecTrace = new SingleRunTraceData(); if (previousTraceData.HasNestedData && i < previousTraceData.NestedData.Count) { //There was previous data that needs loading into the cache lastExecTrace = previousTraceData.NestedData[i]; } else { //We're off the edge of the previous trace window //So just pass in an empty block lastExecTrace = new SingleRunTraceData(); } //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); for (int repIi = 0; repIi < repIndecies.Count; repIi++) { switch (algorithm) { case ZipAlgorithm.Shortest: //If the shortest algorithm is selected this would newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; break; case ZipAlgorithm.Longest: int length = parameters[repIi].Length; if (i < length) { newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; } else { newFormalParams[repIndecies[repIi]] = parameters[repIi].Last(); } break; } } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); SingleRunTraceData cleanRetTrace = new SingleRunTraceData(); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, lastExecTrace, cleanRetTrace); runtimeCore.AddCallSiteGCRoot(CallSiteID, retSVs[i]); retTrace.NestedData[i] = cleanRetTrace; } StackValue ret = runtimeCore.RuntimeMemory.Heap.AllocateArray(retSVs); return ret; } else { //With a cartesian product over an array, we are going to create an array of n //where the n is the product of the next item //We will call the subsequent reductions n times int cartIndex = ri.CartesianIndex; //this will hold the heap elements for all the arrays that are going to be replicated over bool supressArray = false; int retSize; StackValue[] parameters = null; if (formalParameters[cartIndex].IsArray) { DSArray array = runtimeCore.Heap.ToHeapObject<DSArray>(formalParameters[cartIndex]); parameters = array.Values.ToArray(); retSize = parameters.Length; } else { retSize = 1; supressArray = true; } StackValue[] retSVs = new StackValue[retSize]; SingleRunTraceData retTrace = newTraceData; retTrace.NestedData = new List<SingleRunTraceData>(); //this will shadow the SVs as they are created //Populate out the size of the list with default values //@TODO:Luke perf optimisation here for (int i = 0; i < retSize; i++) { retTrace.NestedData.Add(new SingleRunTraceData()); } if (supressArray) { List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); return ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, previousTraceData, newTraceData); } //Now iterate over each of these options for (int i = 0; i < retSize; i++) { //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); if (parameters != null) { //It was an array pack the arg with the current value newFormalParams[cartIndex] = parameters[i]; } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); SingleRunTraceData lastExecTrace; if (previousTraceData.HasNestedData && i < previousTraceData.NestedData.Count) { //There was previous data that needs loading into the cache lastExecTrace = previousTraceData.NestedData[i]; } else if (previousTraceData.HasData && i == 0) { //We've moved up one dimension, and there was a previous run lastExecTrace = new SingleRunTraceData(); lastExecTrace.Data = previousTraceData.GetLeftMostData(); } else { //We're off the edge of the previous trace window //So just pass in an empty block lastExecTrace = new SingleRunTraceData(); } //previousTraceData = lastExecTrace; SingleRunTraceData cleanRetTrace = new SingleRunTraceData(); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, lastExecTrace, cleanRetTrace); runtimeCore.AddCallSiteGCRoot(CallSiteID, retSVs[i]); retTrace.NestedData[i] = cleanRetTrace; } StackValue ret = runtimeCore.RuntimeMemory.Heap.AllocateArray(retSVs); return ret; } }
//Dispatch private StackValue DispatchNew( Context context, List<StackValue> arguments, List<List<ReplicationGuide>> partialReplicationGuides, List<AtLevel> atLevels, StackFrame stackFrame, RuntimeCore runtimeCore) { // Update the CallsiteExecutionState with // TODO: Replace this with the real data UpdateCallsiteExecutionState(null, runtimeCore); Stopwatch sw = new Stopwatch(); sw.Start(); StringBuilder log = new StringBuilder(); log.AppendLine("Method name: " + methodName); #region Get Function Group //@PERF: Possible optimisation point here, to deal with static dispatches that don't need replication analysis //Handle resolution Pass 1: Name -> Method Group FunctionGroup funcGroup = GetFuncGroup(runtimeCore); if (funcGroup == null) { log.AppendLine("Function group not located"); log.AppendLine("Resolution failed in: " + sw.ElapsedMilliseconds); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); return ReportFunctionGroupNotFound(runtimeCore, arguments); } //check accesibility of function group bool methodAccessible = IsFunctionGroupAccessible(runtimeCore, ref funcGroup); if (!methodAccessible) { return ReportMethodNotAccessible(runtimeCore); } //If we got here then the function group got resolved log.AppendLine("Function group resolved: " + funcGroup); #endregion arguments = GetArgumentsAtLevels(arguments, atLevels, runtimeCore).Select(a => a.Argument).ToList(); partialReplicationGuides = PerformRepGuideDemotion(arguments, partialReplicationGuides, runtimeCore); //Replication Control is an ordered list of the elements that we have to replicate over //Ordering implies containment, so element 0 is the outer most forloop, element 1 is nested within it etc. //Take the explicit replication guides and build the replication structure //Turn the replication guides into a guide -> List args data structure var partialInstructions = Replicator.BuildPartialReplicationInstructions(partialReplicationGuides); //Get the fep that are resolved List<FunctionEndPoint> resolvesFeps; List<ReplicationInstruction> replicationInstructions; arguments = PerformRepGuideForcedPromotion(arguments, partialReplicationGuides, runtimeCore); ComputeFeps(log, context, arguments, funcGroup, partialInstructions, partialReplicationGuides, stackFrame, runtimeCore, out resolvesFeps, out replicationInstructions); if (resolvesFeps.Count == 0) { log.AppendLine("Resolution Failed"); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); return ReportMethodNotFoundForArguments(runtimeCore, arguments); } arguments.ForEach(x => runtimeCore.AddCallSiteGCRoot(CallSiteID, x)); StackValue ret = Execute(resolvesFeps, context, arguments, replicationInstructions, stackFrame, runtimeCore, funcGroup); runtimeCore.RemoveCallSiteGCRoot(CallSiteID); return ret; }