Example #1
0
        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;
        }
Example #2
0
        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);
        }