public StackValue Callr(int functionIndex, int classIndex, int depth, ref bool explicitCall, bool isDynamicCall = false, bool hasDebugInfo = false) { isGlobScope = false; ProcedureNode fNode = null; // Comment Jun: this is curently unused but required for stack alignment if (!isDynamicCall) { StackValue svType = rmem.Pop(); runtimeVerify(AddressType.StaticType == svType.optype); int lhsStaticType = (int)svType.metaData.type; } // Pop off number of dimensions indexed into this function call // f()[0][1] -> 2 dimensions StackValue svDim = rmem.Pop(); runtimeVerify(AddressType.ArrayDim == svDim.optype); int fCallDimensions = (int)svDim.opdata; // Jun Comment: The block where the function was declared in StackValue svBlockDeclaration = rmem.Pop(); runtimeVerify(AddressType.BlockIndex == svBlockDeclaration.optype); int blockDeclId = (int)svBlockDeclaration.opdata; // Jun Comment: The block where the function is called from Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != core.RunningBlock); StackValue svBlockCaller = StackValue.BuildBlockIndex(core.RunningBlock); bool isMember = ProtoCore.DSASM.Constants.kInvalidIndex != classIndex; if (isMember) { // Constructor or member function fNode = exe.classTable.ClassNodes[classIndex].vtable.procList[functionIndex]; if (depth > 0) { if (fNode.isConstructor) { string message = String.Format(ProtoCore.RuntimeData.WarningMessage.KCallingConstructorOnInstance, fNode.name); core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kCallingConstructorOnInstance, message); isGlobScope = true; StackValue nullSv = StackValue.Null; return nullSv; } } } else { // Global function fNode = exe.procedureTable[blockDeclId].procList[functionIndex]; } // Build the arg values list List<StackValue> arguments = new List<StackValue>(); List<ProtoCore.ReplicationGuide> replicationGuideList = null; List<List<ProtoCore.ReplicationGuide>> replicationGuides = new List<List<ProtoCore.ReplicationGuide>>(); // Retrive the param values from the stack int stackindex = rmem.Stack.Count - 1; int argtype_i = fNode.argTypeList.Count - 1; int argFrameSize = 0; List<StackValue> dotCallDimensions = new List<StackValue>(); if (fNode.name == ProtoCore.DSASM.Constants.kDotMethodName) { int firstDotArgIndex = stackindex - (ProtoCore.DSASM.Constants.kDotCallArgCount - 1); StackValue svLHS = rmem.Stack[firstDotArgIndex]; arguments.Add(svLHS); argFrameSize = ProtoCore.DSASM.Constants.kDotArgCount; int functionArgsIndex = stackindex - (ProtoCore.DSASM.Constants.kDotCallArgCount - ProtoCore.DSASM.Constants.kDotArgIndexArgCount - 1); StackValue svArrayPtrFunctionArgs = rmem.Stack[functionArgsIndex]; GCRetain(svArrayPtrFunctionArgs); // Retrieve the indexed dimensions into the dot call int arrayDimIndex = stackindex - (ProtoCore.DSASM.Constants.kDotCallArgCount - ProtoCore.DSASM.Constants.kDotArgIndexArrayIndex - 1); StackValue svArrayPtrDimesions = rmem.Stack[arrayDimIndex]; Validity.Assert(svArrayPtrDimesions.optype == AddressType.ArrayPointer); int arrayCountIndex = stackindex - (ProtoCore.DSASM.Constants.kDotCallArgCount - ProtoCore.DSASM.Constants.kDotArgIndexDimCount - 1); StackValue svDimensionCount = rmem.Stack[arrayCountIndex]; Validity.Assert(svDimensionCount.optype == AddressType.Int); // If array dimension were provided then retrive the final pointer if (svDimensionCount.opdata > 0) { HeapElement he = rmem.Heap.Heaplist[(int)svArrayPtrDimesions.opdata]; Validity.Assert(he.VisibleSize == svDimensionCount.opdata); for (int n = 0; n < he.VisibleSize; ++n) { dotCallDimensions.Add(he.Stack[n] /*(int)he.Stack[n].opdata*/); } } } else { for (int p = 0; p < fNode.argTypeList.Count; ++p) { // Must iterate through the args in the stack in reverse as its unknown how many replication guides were pushed StackValue value = rmem.Stack[stackindex--]; ++argFrameSize; arguments.Add(value); if (fNode.name != ProtoCore.DSASM.Constants.kDotArgMethodName) { bool hasGuide = (AddressType.ReplicationGuide == rmem.Stack[stackindex].optype); if (hasGuide) { replicationGuideList = new List<ProtoCore.ReplicationGuide>(); // Retrieve replication guides value = rmem.Stack[stackindex--]; ++argFrameSize; runtimeVerify(AddressType.ReplicationGuide == value.optype); int guides = (int)value.opdata; if (guides > 0) { for (int i = 0; i < guides; ++i) { // Get the replicationguide number from the stack value = rmem.Stack[stackindex--]; Validity.Assert(value.optype == AddressType.Int); int guideNumber = (int)value.opdata; // Get the replication guide property from the stack value = rmem.Stack[stackindex--]; Validity.Assert(value.optype == AddressType.Boolean); bool isLongest = (int)value.opdata == 1 ? true : false; ProtoCore.ReplicationGuide guide = new ReplicationGuide(guideNumber, isLongest); replicationGuideList.Add(guide); ++argFrameSize; } } replicationGuideList.Reverse(); replicationGuides.Add(replicationGuideList); } } } // Pop off frame information rmem.Pop(argFrameSize); } replicationGuides.Reverse(); arguments.Reverse(); Runtime.Context runtimeContext = new Runtime.Context(); #if __PROTOTYPE_ARRAYUPDATE_FUNCTIONCALL // // Comment Jun: Retrieve the indices used to index in an argument // // List<List<int>> indexIntoList // foreach arg in functionNode.args // // Iterate over the symbols in the executing graph node // foreach symbol in executingGraphNode.dependents // List<int> argIndexInto = GetSymbolIndexedIntoList(symbol) // indexIntoList.push(argIndexInto) // end // context.indexlist = indexIntoList // sv = JILDispatch.callsite(function, args, context, ...) // end // if (null != Properties.executingGraphNode && null != Properties.executingGraphNode.dependentList && Properties.executingGraphNode.dependentList.Count > 0 ) { // Save the LHS of this graphnode runtimeContext.ArrayPointer = Properties.executingGraphNode.ArrayPointer; // Iterate over the symbols in the executing graph node for (int n = 0; n < Properties.executingGraphNode.dependentList.Count; n++) { List<int> indexIntoList = new List<int>(); { // Check if the current dependent was indexed into ProtoCore.DSASM.SymbolNode argSymbol = Properties.executingGraphNode.dependentList[n].updateNodeRefList[0].nodeList[0].symbol; if (symbolArrayIndexMap.ContainsKey(argSymbol.name)) { indexIntoList = symbolArrayIndexMap[argSymbol.name]; } } runtimeContext.IndicesIntoArgMap.Add(indexIntoList); } } #endif // Comment Jun: These function do not require replication guides // TODO Jun: Move these conditions or refactor JIL code emission so these checks dont reside here (Post R1) if (ProtoCore.DSASM.Constants.kDotMethodName != fNode.name && ProtoCore.DSASM.Constants.kDotArgMethodName != fNode.name && ProtoCore.DSASM.Constants.kFunctionRangeExpression != fNode.name) { // Comment Jun: If this is a non-dotarg call, cache the guides first and retrieve them on the actual function call // TODO Jun: Ideally, cache the replication guides in the dynamic function node replicationGuides = GetCachedReplicationGuides(core, arguments.Count); } bool isCallingDotArgCall = fNode.name == ProtoCore.DSASM.Constants.kDotArgMethodName; if (isCallingDotArgCall) { // Comment Jun: (Sept 8 2012) Check with Yuke what the intention of this is to the dotarg arguments for (int i = 0; i < arguments.Count; ++i) { GCRetain(arguments[i]); } } // if is dynamic call, the final pointer has been resovled in the ProcessDynamicFunction function StackValue svThisPtr = StackValue.Null; if (depth > 0) { // locals are not yet in the stack so there is no need to account for that in this stack frame if (isDynamicCall) { svThisPtr = rmem.Pop(); } else { svThisPtr = GetFinalPointer(depth); } // if (svThisPtr.optype != AddressType.Pointer) { string message = String.Format(ProtoCore.RuntimeData.WarningMessage.kInvokeMethodOnInvalidObject, fNode.name); core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kDereferencingNonPointer, message); isGlobScope = true; return StackValue.Null; } } else { // There is no depth but check if the function is a member function // If its a member function, the this pointer is required by the core to pass on to the FEP call if (isMember && !fNode.isConstructor && !fNode.isStatic) { // A member function // Get the this pointer as this class instance would have already been cosntructed svThisPtr = rmem.GetAtRelative(rmem.GetStackIndex(ProtoCore.DSASM.StackFrame.kFrameIndexThisPtr)); } else { // Global svThisPtr = ProtoCore.DSASM.StackValue.BuildPointer(ProtoCore.DSASM.Constants.kInvalidPointer); } } if (svThisPtr.optype == AddressType.Pointer && svThisPtr.opdata != Constants.kInvalidIndex && svThisPtr.metaData.type != Constants.kInvalidIndex) { int runtimeClassIndex = (int)svThisPtr.metaData.type; ClassNode runtimeClass = core.ClassTable.ClassNodes[runtimeClassIndex]; if (runtimeClass.IsMyBase(classIndex)) { classIndex = runtimeClassIndex; } } // Build the stackframe //int thisPtr = (int)svThisPtr.opdata; int ci = classIndex; // ProtoCore.DSASM.Constants.kInvalidIndex; // Handled at FEP int fi = ProtoCore.DSASM.Constants.kInvalidIndex; // Handled at FEP int returnAddr = pc + 1; int blockDecl = (int)svBlockDeclaration.opdata; int blockCaller = (int)svBlockCaller.opdata; int framePointer = ProtoCore.DSASM.Constants.kInvalidIndex; framePointer = rmem.FramePointer; bool isInDotArgCall = false; int currentClassIndex = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; int currentFunctionIndex = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; bool isGlobalScope = ProtoCore.DSASM.Constants.kGlobalScope == currentClassIndex && ProtoCore.DSASM.Constants.kGlobalScope == currentFunctionIndex; if (core.ExecMode != InterpreterMode.kExpressionInterpreter) { if (ProtoCore.DSASM.Constants.kGlobalScope != currentFunctionIndex) { int currentFunctionDeclBlock = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunctionBlock).opdata; ProcedureNode currentProcCall = GetProcedureNode(currentFunctionDeclBlock, currentClassIndex, currentFunctionIndex); isInDotArgCall = currentProcCall.name == ProtoCore.DSASM.Constants.kDotArgMethodName; } } if (isGlobalScope || !isInDotArgCall) { if (null != Properties.executingGraphNode) { core.ExecutingGraphnode = Properties.executingGraphNode; } } // Get the cached callsite, creates a new one for a first-time call ProtoCore.CallSite callsite = core.GetCallSite(core.ExecutingGraphnode, classIndex, fNode.name); Validity.Assert(null != callsite); StackFrameType type = StackFrameType.kTypeFunction; int blockDepth = 0; List<StackValue> registers = new List<StackValue>(); SaveRegisters(registers); // Comment Jun: the caller type is the current type in the stackframe StackFrameType callerType = (fepRun) ? StackFrameType.kTypeFunction : StackFrameType.kTypeLanguage; // Get the execution states of the current stackframe int currentScopeClass = ProtoCore.DSASM.Constants.kInvalidIndex; int currentScopeFunction = ProtoCore.DSASM.Constants.kInvalidIndex; GetCallerInformation(out currentScopeClass, out currentScopeFunction); List<bool> execStates = new List<bool>(); // // Comment Jun: // Storing execution states is relevant only if the current scope is a function, // as this mechanism is used to keep track of maintining execution states of recursive calls // This mechanism should also be ignored if the function call is non-recursive as it does not need to maintains state in that case // if (currentScopeFunction != ProtoCore.DSASM.Constants.kGlobalScope) { // Get the instruction stream where the current function resides in StackValue svCurrentFunctionBlockDecl = rmem.GetAtRelative(rmem.GetStackIndex(ProtoCore.DSASM.StackFrame.kFrameIndexFunctionBlock)); Validity.Assert(svCurrentFunctionBlockDecl.optype == AddressType.BlockIndex); AssociativeGraph.DependencyGraph depgraph = exe.instrStreamList[(int)svCurrentFunctionBlockDecl.opdata].dependencyGraph; // Allow only if this is a recursive call // It is recursive if the current function scope is equal to the function to call bool isRecursive = fNode.classScope == currentScopeClass && fNode.procId == currentScopeFunction; if (isRecursive) { // Get the graphnodes of the function from the instruction stream and retrive the execution states execStates = depgraph.GetExecutionStatesAtScope(currentScopeClass, currentScopeFunction); } } // Build the stackfram for the functioncall ProtoCore.DSASM.StackFrame stackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, type, blockDepth, framePointer, registers, execStates); FunctionCounter counter = FindCounter(functionIndex, classIndex, fNode.name); StackValue sv = StackValue.Null; if (core.Options.RecursionChecking) { //Do the recursion check before call if (counter.times < ProtoCore.DSASM.Constants.kRecursionTheshold) //&& counter.sharedCounter < ProtoCore.DSASM.Constants.kRepetationTheshold) { // Build a context object in JILDispatch and call the Dispatch if (counter.times == 0) { counter.times++; core.calledInFunction = true; } else if (counter.times >= 1) { if (fNode.name.ToCharArray()[0] != '%' && fNode.name.ToCharArray()[0] != '_' && !fNode.name.Equals(ProtoCore.DSASM.Constants.kDotMethodName) && core.calledInFunction) { counter.times++; } } if (core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter) { bool isBaseCall = false; core.DebugProps.SetUpCallrForDebug(core, this, fNode, pc, isBaseCall, callsite, arguments, replicationGuides, stackFrame, dotCallDimensions, hasDebugInfo); } sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, core, runtimeContext); } else { FindRecursivePoints(); string message = String.Format(ProtoCore.RuntimeData.WarningMessage.kMethodStackOverflow, core.recursivePoint[0].name); core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kInvalidRecursion, message); core.recursivePoint = new List<FunctionCounter>(); core.funcCounterTable = new List<FunctionCounter>(); sv = StackValue.Null; } } else { if (core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter) { bool isBaseCall = false; if (core.ContinuationStruct.IsFirstCall) { core.DebugProps.SetUpCallrForDebug(core, this, fNode, pc, isBaseCall, callsite, arguments, replicationGuides, stackFrame, dotCallDimensions, hasDebugInfo); } else { core.DebugProps.SetUpCallrForDebug(core, this, fNode, pc, isBaseCall, callsite, core.ContinuationStruct.InitialArguments, replicationGuides, stackFrame, core.ContinuationStruct.InitialDotCallDimensions, hasDebugInfo); } } SX = svBlockDeclaration; stackFrame.SetAt(StackFrame.AbsoluteIndex.kRegisterSX, svBlockDeclaration); //Dispatch without recursion tracking explicitCall = false; isExplicitCall = explicitCall; #if __DEBUG_REPLICATE // TODO: This if block is currently executed only for a replicating function call in Debug Mode (including each of its continuations) // This condition will no longer be required once the same Dispatch function can decide whether to perform a fast dispatch (parallel mode) // OR a Serial/Debug mode dispatch, in which case this same block should work for Serial mode execution w/o the Debug mode check - pratapa if (core.Options.IDEDebugMode) { DebugFrame debugFrame = core.DebugProps.DebugStackFrame.Peek(); //if (debugFrame.IsReplicating || core.ContinuationStruct.IsContinuation) if (debugFrame.IsReplicating) { FunctionEndPoint fep = null; ContinuationStructure cs = core.ContinuationStruct; if (core.Options.ExecutionMode == ProtoCore.ExecutionMode.Serial || core.Options.IDEDebugMode) { // This needs to be done only for the initial argument arrays (ie before the first replicating call) - pratapa if(core.ContinuationStruct.IsFirstCall) { core.ContinuationStruct.InitialDepth = depth; core.ContinuationStruct.InitialPC = pc; core.ContinuationStruct.InitialArguments = arguments; core.ContinuationStruct.InitialDotCallDimensions = dotCallDimensions; for (int i = 0; i < arguments.Count; ++i) { GCUtils.GCRetain(arguments[i], core); } // Hardcoded core.ContinuationStruct.NextDispatchArgs.Add(StackValue.BuildInt(1)); } // The Resolve function is currently hard-coded as a place holder to test debugging replication - pratapa fep = callsite.ResolveForReplication(new ProtoCore.Runtime.Context(), arguments, replicationGuides, stackFrame, core, cs); // TODO: Refactor following steps into new function (ExecWithZeroRI + JILFep.Execute) to be called from here - pratapa // Get final FEP by calling SelectFinalFep() // Update DebugProps with final FEP // Call finalFEP.CoerceParameters() // Setup stackframe // Push Stackframe sv = callsite.ExecuteContinuation(fep, stackFrame, core); core.ContinuationStruct = cs; core.ContinuationStruct.IsFirstCall = true; } } else sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, core); } else #endif sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, core, runtimeContext); if (sv.optype == AddressType.ExplicitCall) { // // Set the interpreter properties for function calls // These are used when performing GC on return // The GC occurs: // 1. In this instruction for implicit calls // 2. In the return instruction // Properties.functionCallArguments = arguments; Properties.functionCallDotCallDimensions = dotCallDimensions; explicitCall = true; isExplicitCall = explicitCall; int entryPC = (int)sv.opdata; CallExplicit(entryPC); } #if __PROTOTYPE_ARRAYUPDATE_FUNCTIONCALL else { if (null != Properties.executingGraphNode) { Properties.executingGraphNode.ArrayPointer = sv; } } #endif } // If the function was called implicitly, The code below assumes this and must be executed if (!explicitCall) { // Restore debug properties after returning from a CALL/CALLR if (core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter) { core.DebugProps.RestoreCallrForNoBreak(core, fNode); } GCDotMethods(fNode.name, ref sv, dotCallDimensions, arguments); DecRefCounter(sv); if (sv.optype == AddressType.ArrayPointer) { // GCReleasePool.Add(sv); } isGlobScope = true; if (fNode.name.ToCharArray()[0] != '%' && fNode.name.ToCharArray()[0] != '_') { core.calledInFunction = false; //@TODO(Gemeng, Luke): Remove me //Console.WriteLine("flag changed \t" + core.calledInFunction); } } return sv; }
private void PopArgumentsFromStack(int argumentCount, ref List<StackValue> arguments, ref List<List<ReplicationGuide>> replicationGuides) { int argFrameSize = 0; int stackindex = rmem.Stack.Count - 1; for (int p = 0; p < argumentCount; ++p) { // Must iterate through the args in the stack in reverse as // its unknown how many replication guides were pushed StackValue value = rmem.Stack[stackindex--]; ++argFrameSize; arguments.Add(value); bool hasGuide = rmem.Stack[stackindex].IsReplicationGuide; if (hasGuide) { var replicationGuideList = new List<ReplicationGuide>(); // Retrieve replication guides value = rmem.Stack[stackindex--]; ++argFrameSize; runtimeVerify(value.IsReplicationGuide); int guides = (int)value.opdata; for (int i = 0; i < guides; ++i) { // Get the replicationguide number from the stack value = rmem.Stack[stackindex--]; Validity.Assert(value.IsInteger); int guideNumber = (int)value.opdata; // Get the replication guide property from the stack value = rmem.Stack[stackindex--]; Validity.Assert(value.IsBoolean); bool isLongest = value.IsBoolean && value.RawBooleanValue; var guide = new ReplicationGuide(guideNumber, isLongest); replicationGuideList.Add(guide); ++argFrameSize; } replicationGuideList.Reverse(); replicationGuides.Add(replicationGuideList); } } rmem.PopFrame(argFrameSize); }