Example #1
0
        public static string Run(string source, ref StringBuilder emitter)
        {
            var context = new Runtime.Context();
            var emitter2 = emitter;

            var astBuilder = new Compiler.AstGenerator();
            var etGenerator = new Compiler.EtGenerator();

            var scope = Scope.CreateGlobal(context);

            Func<object, object> emit = (obj) =>
            {
                emitter2.Append(JsTypeConverter.ToString(obj));
                return null;
            };

            scope.Global(
                "emit",
                emit
            );

            context.SetupGlobals(scope);

            var astNodes = astBuilder.Build(source);
            var compiled = etGenerator.Build(astNodes, context);

            compiled(scope);

            return emitter.ToString();
        }
Example #2
0
        public static string Run(string source)
        {
            var emitter = new StringBuilder();
            var context = new Runtime.Context();

            var astBuilder = new Compiler.AstGenerator();
            var etGenerator = new Compiler.EtGenerator();

            var scope = Scope.CreateGlobal(context);

            Func<object, object> emit = (obj) => { return emitter.Append(JsTypeConverter.ToString(obj)); };
            scope.Global("emit", emit);

            Action<object> assert = (obj) => { Assert.AreEqual((object)true, obj); };
            scope.Global("assert", assert);

            Action<object, object, object> assertEqual = (a, b, msg) => { Assert.AreEqual(a, b, (string)msg); };
            scope.Global("assertEqual", assertEqual);

            Action<object, object> assertFalse = (obj, msg) => { Assert.IsFalse((bool)obj, (string)msg); };
            scope.Global("assertFalse", assertFalse);

            Action<object, object> assertTrue = (obj, msg) => { Assert.IsTrue((bool)obj, (string)msg); };
            scope.Global("assertTrue", assertTrue);

            context.SetupGlobals(scope);

            var astNodes = astBuilder.Build(source);
            var compiled = etGenerator.Build(astNodes, context);

            compiled(scope);

            return emitter.ToString();
        }
Example #3
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 #4
0
        public StackValue Callr(int blockDeclId,
                                int functionIndex, 
                                int classIndex, 
                                ref bool explicitCall, 
                                bool isDynamicCall = false, 
                                bool hasDebugInfo = false)
        {
            // This is curently unused but required for stack alignment
            var svDepth = rmem.Pop();
            int depth = (int)svDepth.opdata;

            if (!isDynamicCall)
            {
                StackValue svType = rmem.Pop();
                runtimeVerify(svType.IsStaticType);
            }

            ProcedureNode fNode = null;

            // Pop off number of dimensions indexed into this function call
            // f()[0][1] -> 2 dimensions
            StackValue svDim = rmem.Pop();
            runtimeVerify(svDim.IsArrayDimension);

            bool isCallingMemberFunction = Constants.kInvalidIndex != classIndex;
            if (isCallingMemberFunction)
            {
                fNode = exe.classTable.ClassNodes[classIndex].ProcTable.Procedures[functionIndex];

                if (depth > 0 && fNode.IsConstructor)
                {
                    string message = String.Format(Resources.KCallingConstructorOnInstance, fNode.Name);
                    runtimeCore.RuntimeStatus.LogWarning(WarningID.kCallingConstructorOnInstance, message);
                    return StackValue.Null;
                }
            }
            else
            {
                // Global function
                fNode = exe.procedureTable[blockDeclId].Procedures[functionIndex];
            }

            // Build the arg values list
            var arguments = new List<StackValue>();
            var replicationGuides = new List<List<ReplicationGuide>>();

            // Retrive the param values from the stack
            int stackindex = rmem.Stack.Count - 1;

            List<StackValue> dotCallDimensions = new List<StackValue>();
            if (fNode.Name.Equals(Constants.kDotMethodName))
            {
                int firstDotArgIndex = stackindex - (Constants.kDotCallArgCount - 1);
                StackValue svLHS = rmem.Stack[firstDotArgIndex];
                arguments.Add(svLHS);

                // Retrieve the indexed dimensions into the dot call
                int arrayDimIndex = stackindex - (Constants.kDotCallArgCount - Constants.kDotArgIndexArrayIndex - 1);
                StackValue svArrayPtrDimesions = rmem.Stack[arrayDimIndex];
                Validity.Assert(svArrayPtrDimesions.IsArray);

                int arrayCountIndex = stackindex - (Constants.kDotCallArgCount - Constants.kDotArgIndexDimCount - 1);
                StackValue svDimensionCount = rmem.Stack[arrayCountIndex];
                Validity.Assert(svDimensionCount.IsInteger);

                // If array dimension were provided then retrive the final pointer 
                if (svDimensionCount.opdata > 0)
                {
                    var dimArray = rmem.Heap.ToHeapObject<DSArray>(svArrayPtrDimesions);
                    Validity.Assert(dimArray.Count == svDimensionCount.opdata);
                    dotCallDimensions.AddRange(dimArray.Values);
                }
            }
            else
            {
                PopArgumentsFromStack(fNode.ArgumentTypes.Count, ref arguments, ref replicationGuides);
            }

            replicationGuides.Reverse();
            arguments.Reverse();

            Runtime.Context runtimeContext = new Runtime.Context();

            // 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 (Constants.kDotMethodName != fNode.Name
                && Constants.kFunctionRangeExpression != fNode.Name)
            {
                // Comment Jun: If this is a non-dot 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(arguments.Count);
            }

            // 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.IsPointer)
                {
                    string message = String.Format(Resources.kInvokeMethodOnInvalidObject, fNode.Name);
                    runtimeCore.RuntimeStatus.LogWarning(WarningID.kDereferencingNonPointer, message);
                    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 (isCallingMemberFunction && !fNode.IsConstructor && !fNode.IsStatic)
                {
                    // A member function
                    // Get the this pointer as this class instance would have already been cosntructed
                    svThisPtr = rmem.CurrentStackFrame.ThisPtr;
                }
                else if (fNode.Name.Equals(Constants.kInlineConditionalMethodName))
                {
                    // The built-in inlinecondition function is global but it is treated as a conditional execution rather than a normal function call
                    // This is why the class scope  needs to be preserved such that the auto-generated language blocks in an inline conditional can still refer to member functions and properties
                    svThisPtr = rmem.CurrentStackFrame.ThisPtr;
                }
                else
                {
                    // Global
                    svThisPtr = StackValue.BuildPointer(Constants.kInvalidPointer);
                }
            }

            if (svThisPtr.IsPointer &&
                svThisPtr.opdata != Constants.kInvalidIndex &&
                svThisPtr.metaData.type != Constants.kInvalidIndex)
            {
                int runtimeClassIndex = svThisPtr.metaData.type;
                ClassNode runtimeClass = exe.classTable.ClassNodes[runtimeClassIndex];
                if (runtimeClass.IsMyBase(classIndex))
                {
                    classIndex = runtimeClassIndex;
                }
            }

            // Build the stackframe
            //int thisPtr = (int)svThisPtr.opdata;
            int ci = classIndex; // Constants.kInvalidIndex;   // Handled at FEP
            int fi = Constants.kInvalidIndex;   // Handled at FEP

            int returnAddr = pc + 1;

            int blockDecl = blockDeclId;

            if (null != Properties.executingGraphNode)
            {
                exe.ExecutingGraphnode = Properties.executingGraphNode;
            }

            // Get the cached callsite, creates a new one for a first-time call
            CallSite callsite = runtimeCore.RuntimeData.GetCallSite(
                exe.ExecutingGraphnode, 
                classIndex, 
                fNode.Name, 
                exe,
                runtimeCore.RunningBlock, 
                runtimeCore.Options, 
                runtimeCore.RuntimeStatus);
            Validity.Assert(null != callsite);

            List<StackValue> registers = new List<StackValue>();
            SaveRegisters(registers);

            // Get the execution states of the current stackframe
            int currentScopeClass = Constants.kInvalidIndex;
            int currentScopeFunction = Constants.kInvalidIndex;
            GetCallerInformation(out currentScopeClass, out currentScopeFunction);


            // Handle execution states at the FEP
            var stackFrame = new StackFrame(svThisPtr, 
                                            ci, 
                                            fi, 
                                            returnAddr, 
                                            blockDecl,
                                            runtimeCore.RunningBlock, 
                                            fepRun ? StackFrameType.kTypeFunction : StackFrameType.kTypeLanguage, 
                                            StackFrameType.kTypeFunction, 
                                            0, 
                                            rmem.FramePointer, 
                                            registers, 
                                            null);

            FunctionCounter counter = FindCounter(functionIndex, classIndex, fNode.Name);
            StackValue sv = StackValue.Null;

            if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter)
            {
                if (runtimeCore.ContinuationStruct.IsFirstCall)
                {
                    runtimeCore.DebugProps.SetUpCallrForDebug(
                                                       runtimeCore,
                                                       this,
                                                       fNode,
                                                       pc,
                                                       false,
                                                       callsite,
                                                       arguments,
                                                       replicationGuides,
                                                       stackFrame,
                                                       dotCallDimensions,
                                                       hasDebugInfo);
                }
                else
                {
                    runtimeCore.DebugProps.SetUpCallrForDebug(
                                                       runtimeCore,
                                                       this,
                                                       fNode,
                                                       pc,
                                                       false,
                                                       callsite,
                                                       runtimeCore.ContinuationStruct.InitialArguments,
                                                       replicationGuides,
                                                       stackFrame,
                                                       runtimeCore.ContinuationStruct.InitialDotCallDimensions,
                                                       hasDebugInfo);
                }
            }

            SX = StackValue.BuildBlockIndex(blockDeclId);
            stackFrame.SX = SX;

            //Dispatch without recursion tracking 
            explicitCall = false;
            IsExplicitCall = explicitCall;

            sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, runtimeCore, runtimeContext);
            if (sv.IsExplicitCall)
            {
                //
                // 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 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 (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter)
                {
                    runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, fNode);
                }

                GCDotMethods(fNode.Name, ref sv, dotCallDimensions, arguments);

                if (fNode.Name.ToCharArray()[0] != '%' && fNode.Name.ToCharArray()[0] != '_')
                {
                    exe.calledInFunction = false;
                }
            }
            return sv;
        }
Example #5
0
        public StackValue Callr(int blockDeclId,
                                int functionIndex, 
                                int classIndex, 
                                ref bool explicitCall, 
                                bool isDynamicCall = false, 
                                bool hasDebugInfo = false)
        {
            // This is curently unused but required for stack alignment
            var svDepth = rmem.Pop();
            int depth = (int)svDepth.opdata;

            if (!isDynamicCall)
            {
                StackValue svType = rmem.Pop();
                runtimeVerify(svType.IsStaticType);
            }

            ProcedureNode fNode = null;

            // Pop off number of dimensions indexed into this function call
            // f()[0][1] -> 2 dimensions
            StackValue svDim = rmem.Pop();
            runtimeVerify(svDim.IsArrayDimension);

            bool isCallingMemberFunction = Constants.kInvalidIndex != classIndex;
            if (isCallingMemberFunction)
            {
                fNode = exe.classTable.ClassNodes[classIndex].ProcTable.procList[functionIndex];

                if (depth > 0 && fNode.IsConstructor)
                {
                    string message = String.Format(Resources.KCallingConstructorOnInstance, fNode.Name);
                    runtimeCore.RuntimeStatus.LogWarning(WarningID.kCallingConstructorOnInstance, message);
                    return StackValue.Null;
                }
            }
            else
            {
                // Global function
                fNode = exe.procedureTable[blockDeclId].procList[functionIndex];
            }

            // Build the arg values list
            var arguments = new List<StackValue>();
            var replicationGuides = new List<List<ReplicationGuide>>();

            // Retrive the param values from the stack
            int stackindex = rmem.Stack.Count - 1;

            List<StackValue> dotCallDimensions = new List<StackValue>();
            if (fNode.Name.Equals(Constants.kDotMethodName))
            {
                int firstDotArgIndex = stackindex - (Constants.kDotCallArgCount - 1);
                StackValue svLHS = rmem.Stack[firstDotArgIndex];
                arguments.Add(svLHS);

                // Retrieve the indexed dimensions into the dot call
                int arrayDimIndex = stackindex - (Constants.kDotCallArgCount - Constants.kDotArgIndexArrayIndex - 1);
                StackValue svArrayPtrDimesions = rmem.Stack[arrayDimIndex];
                Validity.Assert(svArrayPtrDimesions.IsArray);

                int arrayCountIndex = stackindex - (Constants.kDotCallArgCount - Constants.kDotArgIndexDimCount - 1);
                StackValue svDimensionCount = rmem.Stack[arrayCountIndex];
                Validity.Assert(svDimensionCount.IsInteger);

                // If array dimension were provided then retrive the final pointer 
                if (svDimensionCount.opdata > 0)
                {
                    var dimArray = rmem.Heap.ToHeapObject<DSArray>(svArrayPtrDimesions);
                    Validity.Assert(dimArray.Count == svDimensionCount.opdata);
                    dotCallDimensions.AddRange(dimArray.Values);
                }
            }
            else
            {
                PopArgumentsFromStack(fNode.ArgumentTypes.Count, ref arguments, ref replicationGuides);
            }

            replicationGuides.Reverse();
            arguments.Reverse();

            Runtime.Context runtimeContext = new Runtime.Context();

            // 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 (Constants.kDotMethodName != fNode.Name
                && Constants.kFunctionRangeExpression != fNode.Name)
            {
                // Comment Jun: If this is a non-dot 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(arguments.Count);
            }

            // 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.IsPointer)
                {
                    string message = String.Format(Resources.kInvokeMethodOnInvalidObject, fNode.Name);
                    runtimeCore.RuntimeStatus.LogWarning(WarningID.kDereferencingNonPointer, message);
                    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 (isCallingMemberFunction && !fNode.IsConstructor && !fNode.IsStatic)
                {
                    // A member function
                    // Get the this pointer as this class instance would have already been cosntructed
                    svThisPtr = rmem.CurrentStackFrame.ThisPtr;
                }
                else if (fNode.Name.Equals(Constants.kInlineConditionalMethodName))
                {
                    // The built-in inlinecondition function is global but it is treated as a conditional execution rather than a normal function call
                    // This is why the class scope  needs to be preserved such that the auto-generated language blocks in an inline conditional can still refer to member functions and properties
                    svThisPtr = rmem.CurrentStackFrame.ThisPtr;
                }
                else
                {
                    // Global
                    svThisPtr = StackValue.BuildPointer(Constants.kInvalidPointer);
                }
            }

            if (svThisPtr.IsPointer &&
                svThisPtr.opdata != Constants.kInvalidIndex &&
                svThisPtr.metaData.type != Constants.kInvalidIndex)
            {
                int runtimeClassIndex = svThisPtr.metaData.type;
                ClassNode runtimeClass = exe.classTable.ClassNodes[runtimeClassIndex];
                if (runtimeClass.IsMyBase(classIndex))
                {
                    classIndex = runtimeClassIndex;
                }
            }

            // Build the stackframe
            //int thisPtr = (int)svThisPtr.opdata;
            int ci = classIndex; // Constants.kInvalidIndex;   // Handled at FEP
            int fi = Constants.kInvalidIndex;   // Handled at FEP

            int returnAddr = pc + 1;

            int blockDecl = blockDeclId;

            if (null != Properties.executingGraphNode)
            {
                exe.ExecutingGraphnode = Properties.executingGraphNode;
            }

            // Get the cached callsite, creates a new one for a first-time call
            CallSite callsite = runtimeCore.RuntimeData.GetCallSite(
                exe.ExecutingGraphnode, 
                classIndex, 
                fNode.Name, 
                exe,
                runtimeCore.RunningBlock, 
                runtimeCore.Options, 
                runtimeCore.RuntimeStatus);
            Validity.Assert(null != callsite);

            List<StackValue> registers = new List<StackValue>();
            SaveRegisters(registers);

            // Get the execution states of the current stackframe
            int currentScopeClass = Constants.kInvalidIndex;
            int currentScopeFunction = Constants.kInvalidIndex;
            GetCallerInformation(out currentScopeClass, out currentScopeFunction);


            // Handle execution states at the FEP
            var stackFrame = new StackFrame(svThisPtr, 
                                            ci, 
                                            fi, 
                                            returnAddr, 
                                            blockDecl,
                                            runtimeCore.RunningBlock, 
                                            fepRun ? StackFrameType.kTypeFunction : StackFrameType.kTypeLanguage, 
                                            StackFrameType.kTypeFunction, 
                                            0, 
                                            rmem.FramePointer, 
                                            registers, 
                                            null);

            FunctionCounter counter = FindCounter(functionIndex, classIndex, fNode.Name);
            StackValue sv = StackValue.Null;


            if (runtimeCore.Options.RecursionChecking)
            {
                //Do the recursion check before call
                if (counter.times < Constants.kRecursionTheshold) //&& counter.sharedCounter < Constants.kRepetationTheshold)
                {

                    // Build a context object in JILDispatch and call the Dispatch
                    if (counter.times == 0)
                    {
                        counter.times++;
                        exe.calledInFunction = true;
                    }

                    else if (counter.times >= 1)
                    {
                        if (fNode.Name.ToCharArray()[0] != '%' && fNode.Name.ToCharArray()[0] != '_' && !fNode.Name.Equals(Constants.kDotMethodName) && exe.calledInFunction)
                        {
                            counter.times++;
                        }
                    }


                    if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter)
                    {
                        runtimeCore.DebugProps.SetUpCallrForDebug(runtimeCore, this, fNode, pc, false, callsite, arguments, replicationGuides, stackFrame, dotCallDimensions, hasDebugInfo);
                    }

                    sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, runtimeCore, runtimeContext);
                }
                else
                {
                    FindRecursivePoints();
                    string message = String.Format(Resources.kMethodStackOverflow, exe.recursivePoint[0].name);
                    runtimeCore.RuntimeStatus.LogWarning(WarningID.kInvalidRecursion, message);

                    exe.recursivePoint = new List<FunctionCounter>();
                    exe.funcCounterTable = new List<FunctionCounter>();
                    sv = StackValue.Null;
                }
            }
            else
            {
                if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter)
                {
                    if (runtimeCore.ContinuationStruct.IsFirstCall)
                    {
                        runtimeCore.DebugProps.SetUpCallrForDebug(
                                                           runtimeCore,
                                                           this, 
                                                           fNode, 
                                                           pc, 
                                                           false, 
                                                           callsite, 
                                                           arguments, 
                                                           replicationGuides, 
                                                           stackFrame, 
                                                           dotCallDimensions, 
                                                           hasDebugInfo);
                    }
                    else
                    {
                        runtimeCore.DebugProps.SetUpCallrForDebug( 
                                                           runtimeCore,
                                                           this, 
                                                           fNode, 
                                                           pc, 
                                                           false, 
                                                           callsite, 
                                                           runtimeCore.ContinuationStruct.InitialArguments, 
                                                           replicationGuides, 
                                                           stackFrame,
                                                           runtimeCore.ContinuationStruct.InitialDotCallDimensions, 
                                                           hasDebugInfo);
                    }
                }

                SX = StackValue.BuildBlockIndex(blockDeclId);
                stackFrame.SX = SX;

                //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 (runtimeCore.RuntimeOptions.IDEDebugMode)
                {
                    DebugFrame debugFrame = runtimeCore.DebugProps.DebugStackFrame.Peek();

                    //if (debugFrame.IsReplicating || runtimeCore.ContinuationStruct.IsContinuation)
                    if (debugFrame.IsReplicating)
                    {
                        FunctionEndPoint fep = null;
                        ContinuationStructure cs = runtimeCore.ContinuationStruct;

                        if (runtimeCore.RuntimeOptions.ExecutionMode == ProtoCore.ExecutionMode.Serial || runtimeCore.RuntimeOptions.IDEDebugMode)
                        {
                            // This needs to be done only for the initial argument arrays (ie before the first replicating call) - pratapa
                            if(runtimeCore.ContinuationStruct.IsFirstCall)
                            {
                                runtimeCore.ContinuationStruct.InitialDepth = depth;
                                runtimeCore.ContinuationStruct.InitialPC = pc;
                                runtimeCore.ContinuationStruct.InitialArguments = arguments;
                                runtimeCore.ContinuationStruct.InitialDotCallDimensions = dotCallDimensions;

                                for (int i = 0; i < arguments.Count; ++i)
                                {
                                    GCUtils.GCRetain(arguments[i], core);
                                }

                                // Hardcoded
                                runtimeCore.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);

                            runtimeCore.ContinuationStruct = cs;
                            runtimeCore.ContinuationStruct.IsFirstCall = true;

                        }
                    }
                    else
                        sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, core);
                }
                else
#endif
                sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, runtimeCore, runtimeContext);

                if (sv.IsExplicitCall)
                {
                    //
                    // 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 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 (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter)
                {
                    runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, fNode);
                }

                GCDotMethods(fNode.Name, ref sv, dotCallDimensions, arguments);

                if (fNode.Name.ToCharArray()[0] != '%' && fNode.Name.ToCharArray()[0] != '_')
                {
                    exe.calledInFunction = false;
                }
            }
            return sv;
        }
        public override StackValue Execute(Runtime.Context c, List <StackValue> formalParameters, StackFrame stackFrame, RuntimeCore runtimeCore)
        {
            if (mInterpreter == null)
            {
                Init(runtimeCore);
            }

            if (mFunctionPointer == null)
            {
                return(StackValue.Null);
            }

            if (stackFrame != null)
            {
                StackValue svThisPtr = stackFrame.ThisPtr;

                // Check if this is a 'this' pointer function overload that was generated by the compiler
                if (null != mFNode && mFNode.IsAutoGeneratedThisProc)
                {
                    int  thisPtrIndex = 0;
                    bool isStaticCall = svThisPtr.IsPointer && Constants.kInvalidPointer == svThisPtr.Pointer;
                    if (isStaticCall)
                    {
                        stackFrame.ThisPtr = formalParameters[thisPtrIndex];
                    }

                    // Comment Jun: Execute() can handle a null this pointer.
                    // But since we don't even need to to reach there if we don't have a valid this pointer, then just return null
                    if (formalParameters[thisPtrIndex].IsNull)
                    {
                        runtimeCore.RuntimeStatus.LogWarning(
                            Runtime.WarningID.DereferencingNonPointer, Resources.kDereferencingNonPointer);
                        return(StackValue.Null);
                    }

                    // These are the op types allowed.
                    Validity.Assert(formalParameters[thisPtrIndex].IsPointer ||
                                    formalParameters[thisPtrIndex].IsDefaultArgument);

                    // Make sure we to pass a pointer to unmarshal.
                    if (formalParameters[thisPtrIndex].IsPointer)
                    {
                        svThisPtr = formalParameters[thisPtrIndex];
                    }

                    formalParameters.RemoveAt(thisPtrIndex);
                }

                formalParameters.Add(svThisPtr);
            }

            Object     ret = mFunctionPointer.Execute(c, mInterpreter, formalParameters);
            StackValue op;

            if (ret == null)
            {
                op = StackValue.Null;
            }
            else if (ret is StackValue)
            {
                op = (StackValue)ret;
            }
            else if (ret is Int64 || ret is int)
            {
                op = StackValue.BuildInt((Int64)ret);
            }
            else if (ret is double)
            {
                op = StackValue.BuildDouble((double)ret);
            }
            else
            {
                throw new ArgumentException(string.Format("FFI: incorrect return type {0} from external function {1}:{2}",
                                                          activation.ReturnType.Name, activation.ModuleName, activation.FunctionName));
            }
            return(op);
        }